github.com/enetx/g@v1.0.80/slice.go (about)

     1  package g
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"slices"
     7  	"strings"
     8  
     9  	"github.com/enetx/g/cmp"
    10  	"github.com/enetx/g/f"
    11  	"github.com/enetx/g/pkg/rand"
    12  )
    13  
    14  // NewSlice creates a new Slice of the given generic type T with the specified length and
    15  // capacity.
    16  // The size variadic parameter can have zero, one, or two integer values.
    17  // If no values are provided, an empty Slice with a length and capacity of 0 is returned.
    18  // If one value is provided, it sets both the length and capacity of the Slice.
    19  // If two values are provided, the first value sets the length and the second value sets the
    20  // capacity.
    21  //
    22  // Parameters:
    23  //
    24  // - size ...Int: A variadic parameter specifying the length and/or capacity of the Slice
    25  //
    26  // Returns:
    27  //
    28  // - Slice[T]: A new Slice of the specified generic type T with the given length and capacity
    29  //
    30  // Example usage:
    31  //
    32  //	s1 := g.NewSlice[int]()        // Creates an empty Slice of type int
    33  //	s2 := g.NewSlice[int](5)       // Creates an Slice with length and capacity of 5
    34  //	s3 := g.NewSlice[int](3, 10)   // Creates an Slice with length of 3 and capacity of 10
    35  func NewSlice[T any](size ...Int) Slice[T] {
    36  	var (
    37  		length   Int
    38  		capacity Int
    39  	)
    40  
    41  	switch {
    42  	case len(size) > 1:
    43  		length, capacity = size[0], size[1]
    44  	case len(size) == 1:
    45  		length, capacity = size[0], size[0]
    46  	}
    47  
    48  	return make(Slice[T], length, capacity)
    49  }
    50  
    51  // SliceOf creates a new generic slice containing the provided elements.
    52  func SliceOf[T any](slice ...T) Slice[T] { return slice }
    53  
    54  // SliceMap applies the given function to each element of a Slice and returns a new Slice
    55  // containing the transformed values.
    56  //
    57  // Parameters:
    58  //
    59  // - sl: The input Slice.
    60  //
    61  // - fn: The function to apply to each element of the input Slice.
    62  //
    63  // Returns:
    64  //
    65  // A new Slice containing the results of applying the function to each element of the input Slice.
    66  func SliceMap[T, U any](sl Slice[T], fn func(T) U) Slice[U] { return sliceMap(sl.Iter(), fn).Collect() }
    67  
    68  // Iter returns an iterator (SeqSlice[T]) for the Slice, allowing for sequential iteration
    69  // over its elements. It is commonly used in combination with higher-order functions,
    70  // such as 'ForEach', to perform operations on each element of the Slice.
    71  //
    72  // Returns:
    73  //
    74  // A SeqSlice[T], which can be used for sequential iteration over the elements of the Slice.
    75  //
    76  // Example usage:
    77  //
    78  //	slice := g.Slice[int]{1, 2, 3, 4, 5}
    79  //	iterator := slice.Iter()
    80  //	iterator.ForEach(func(element int) {
    81  //		// Perform some operation on each element
    82  //		fmt.Println(element)
    83  //	})
    84  //
    85  // The 'Iter' method provides a convenient way to traverse the elements of a Slice
    86  // in a functional style, enabling operations like mapping or filtering.
    87  func (sl Slice[T]) Iter() SeqSlice[T] { return ToSeqSlice(sl) }
    88  
    89  // AsAny converts each element of the slice to the 'any' type.
    90  // It returns a new slice containing the elements as 'any' g.Slice[any].
    91  //
    92  // Note: AsAny is useful when you want to work with a slice of a specific type as a slice of 'any'.
    93  // It can be particularly handy in conjunction with Flatten to work with nested slices of different types.
    94  func (sl Slice[T]) AsAny() Slice[any] { return SliceMap(sl, func(t T) any { return any(t) }) }
    95  
    96  // Fill fills the slice with the specified value.
    97  // This function is useful when you want to create an Slice with all elements having the same
    98  // value.
    99  // This method modifies the original slice in place.
   100  //
   101  // Parameters:
   102  //
   103  // - val T: The value to fill the Slice with.
   104  //
   105  // Returns:
   106  //
   107  // - Slice[T]: A reference to the original Slice filled with the specified value.
   108  //
   109  // Example usage:
   110  //
   111  //	slice := g.Slice[int]{0, 0, 0}
   112  //	slice.Fill(5)
   113  //
   114  // The modified slice will now contain: 5, 5, 5.
   115  func (sl Slice[T]) Fill(val T) {
   116  	for i := range sl {
   117  		sl[i] = val
   118  	}
   119  }
   120  
   121  // Index returns the index of the first occurrence of the specified value in the slice, or -1 if
   122  // not found.
   123  func (sl Slice[T]) Index(val T) Int {
   124  	switch s := any(sl).(type) {
   125  	case Slice[Int]:
   126  		return Int(slices.Index(s, any(val).(Int)))
   127  	case Slice[String]:
   128  		return Int(slices.Index(s, any(val).(String)))
   129  	case Slice[Float]:
   130  		return Int(slices.Index(s, any(val).(Float)))
   131  	case Slice[string]:
   132  		return Int(slices.Index(s, any(val).(string)))
   133  	case Slice[bool]:
   134  		return Int(slices.Index(s, any(val).(bool)))
   135  	case Slice[int]:
   136  		return Int(slices.Index(s, any(val).(int)))
   137  	case Slice[int8]:
   138  		return Int(slices.Index(s, any(val).(int8)))
   139  	case Slice[int16]:
   140  		return Int(Int(slices.Index(s, any(val).(int16))))
   141  	case Slice[int32]:
   142  		return Int(slices.Index(s, any(val).(int32)))
   143  	case Slice[int64]:
   144  		return Int(slices.Index(s, any(val).(int64)))
   145  	case Slice[uint]:
   146  		return Int(slices.Index(s, any(val).(uint)))
   147  	case Slice[uint8]:
   148  		return Int(slices.Index(s, any(val).(uint8)))
   149  	case Slice[uint16]:
   150  		return Int(slices.Index(s, any(val).(uint16)))
   151  	case Slice[uint32]:
   152  		return Int(slices.Index(s, any(val).(uint32)))
   153  	case Slice[uint64]:
   154  		return Int(slices.Index(s, any(val).(uint64)))
   155  	case Slice[float32]:
   156  		return Int(slices.Index(s, any(val).(float32)))
   157  	case Slice[float64]:
   158  		return Int(slices.Index(s, any(val).(float64)))
   159  	default:
   160  		return sl.IndexBy(f.Eqd(val))
   161  	}
   162  }
   163  
   164  // IndexBy returns the index of the first element in the slice
   165  // satisfying the custom comparison function provided by the user.
   166  // It iterates through the slice and applies the comparison function to each element and the target value.
   167  // If the comparison function returns true for any pair of elements, it returns the index of that element.
   168  // If no such element is found, it returns -1.
   169  func (sl Slice[T]) IndexBy(fn func(t T) bool) Int { return Int(slices.IndexFunc(sl, fn)) }
   170  
   171  // RandomSample returns a new slice containing a random sample of elements from the original slice.
   172  // The sampling is done without replacement, meaning that each element can only appear once in the result.
   173  //
   174  // Parameters:
   175  //
   176  // - sequence int: The number of unique elements to include in the random sample.
   177  //
   178  // Returns:
   179  //
   180  // - Slice[T]: A new Slice containing the random sample of unique elements.
   181  //
   182  // Example usage:
   183  //
   184  //	slice := g.Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9}
   185  //	sample := slice.RandomSample(3)
   186  //
   187  // The resulting sample will contain 3 unique elements randomly selected from the original slice.
   188  func (sl Slice[T]) RandomSample(sequence Int) Slice[T] {
   189  	if sequence.Gte(sl.Len()) {
   190  		return sl
   191  	}
   192  
   193  	clone := sl.Clone()
   194  	clone.Shuffle()
   195  
   196  	return clone[0:sequence]
   197  }
   198  
   199  // RandomRange returns a new slice containing a random sample of elements from a subrange of the original slice.
   200  // The sampling is done without replacement, meaning that each element can only appear once in the result.
   201  func (sl Slice[T]) RandomRange(from, to Int) Slice[T] {
   202  	if from < 0 {
   203  		from = 0
   204  	}
   205  
   206  	if to < 0 || to > sl.Len() {
   207  		to = sl.Len()
   208  	}
   209  
   210  	if from > to {
   211  		from = to
   212  	}
   213  
   214  	return sl.RandomSample(from.RandomRange(to))
   215  }
   216  
   217  // Insert inserts values at the specified index in the slice and returns the resulting slice.
   218  // The original slice remains unchanged.
   219  //
   220  // Parameters:
   221  //
   222  // - i Int: The index at which to insert the new values.
   223  //
   224  // - values ...T: A variadic list of values to insert at the specified index.
   225  //
   226  // Returns:
   227  //
   228  // - Slice[T]: A new Slice containing the original elements and the inserted values.
   229  //
   230  // Example usage:
   231  //
   232  //	slice := g.Slice[string]{"a", "b", "c", "d"}
   233  //	newSlice := slice.Insert(2, "e", "f")
   234  //
   235  // The resulting newSlice will be: ["a", "b", "e", "f", "c", "d"].
   236  func (sl Slice[T]) Insert(i Int, values ...T) Slice[T] { return sl.Replace(i, i, values...) }
   237  
   238  // InsertInPlace inserts values at the specified index in the slice and modifies the original
   239  // slice.
   240  //
   241  // Parameters:
   242  //
   243  // - i Int: The index at which to insert the new values.
   244  //
   245  // - values ...T: A variadic list of values to insert at the specified index.
   246  //
   247  // Example usage:
   248  //
   249  //	slice := g.Slice[string]{"a", "b", "c", "d"}
   250  //	slice.InsertInPlace(2, "e", "f")
   251  //
   252  // The resulting slice will be: ["a", "b", "e", "f", "c", "d"].
   253  func (sl *Slice[T]) InsertInPlace(i Int, values ...T) { sl.ReplaceInPlace(i, i, values...) }
   254  
   255  // Replace replaces the elements of sl[i:j] with the given values, and returns
   256  // a new slice with the modifications. The original slice remains unchanged.
   257  // Replace panics if sl[i:j] is not a valid slice of sl.
   258  //
   259  // Parameters:
   260  //
   261  // - i Int: The starting index of the slice to be replaced.
   262  //
   263  // - j Int: The ending index of the slice to be replaced.
   264  //
   265  // - values ...T: A variadic list of values to replace the existing slice.
   266  //
   267  // Returns:
   268  //
   269  // - Slice[T]: A new Slice containing the original elements with the specified elements replaced.
   270  //
   271  // Example usage:
   272  //
   273  //	slice := g.Slice[string]{"a", "b", "c", "d"}
   274  //	newSlice := slice.Replace(1, 3, "e", "f")
   275  //
   276  // The original slice remains ["a", "b", "c", "d"], and the newSlice will be: ["a", "e", "f", "d"].
   277  func (sl Slice[T]) Replace(i, j Int, values ...T) Slice[T] {
   278  	i = sl.bound(i)
   279  	j = sl.bound(j)
   280  
   281  	if i > j {
   282  		return NewSlice[T]()
   283  	}
   284  
   285  	total := sl[:i].Len() + Int(len(values)) + sl[j:].Len()
   286  	slice := NewSlice[T](total)
   287  
   288  	copy(slice, sl[:i])
   289  	copy(slice[i:], values)
   290  	copy(slice[i+Int(len(values)):], sl[j:])
   291  
   292  	return slice
   293  }
   294  
   295  // ReplaceInPlace replaces the elements of sl[i:j] with the given values,
   296  // and modifies the original slice in place. ReplaceInPlace panics if sl[i:j]
   297  // is not a valid slice of sl.
   298  //
   299  // Parameters:
   300  //
   301  // - i int: The starting index of the slice to be replaced.
   302  //
   303  // - j int: The ending index of the slice to be replaced.
   304  //
   305  // - values ...T: A variadic list of values to replace the existing slice.
   306  //
   307  // Example usage:
   308  //
   309  //	slice := g.Slice[string]{"a", "b", "c", "d"}
   310  //	slice.ReplaceInPlace(1, 3, "e", "f")
   311  //
   312  // After the ReplaceInPlace operation, the resulting slice will be: ["a", "e", "f", "d"].
   313  func (sl *Slice[T]) ReplaceInPlace(i, j Int, values ...T) {
   314  	i = sl.bound(i)
   315  	j = sl.bound(j)
   316  
   317  	if i > j {
   318  		*sl = (*sl)[:0]
   319  		return
   320  	}
   321  
   322  	if i == j {
   323  		if len(values) > 0 {
   324  			*sl = append((*sl)[:i], append(values, (*sl)[i:]...)...)
   325  		}
   326  
   327  		return
   328  	}
   329  
   330  	diff := Int(len(values)) - (j - i)
   331  
   332  	if diff > 0 {
   333  		*sl = append(*sl, NewSlice[T](diff)...)
   334  	}
   335  
   336  	copy((*sl)[i+Int(len(values)):], (*sl)[j:])
   337  	copy((*sl)[i:], values)
   338  
   339  	if diff < 0 {
   340  		*sl = (*sl)[:(*sl).Len()+diff]
   341  	}
   342  }
   343  
   344  // AddUnique appends unique elements from the provided arguments to the current slice.
   345  //
   346  // The function iterates over the provided elements and checks if they are already present
   347  // in the slice. If an element is not already present, it is appended to the slice. The
   348  // resulting slice is returned, containing the unique elements from both the original
   349  // slice and the provided elements.
   350  //
   351  // Parameters:
   352  //
   353  // - elems (...T): A variadic list of elements to be appended to the slice.
   354  //
   355  // Returns:
   356  //
   357  // - Slice[T]: A new slice containing the unique elements from both the original slice
   358  // and the provided elements.
   359  //
   360  // Example usage:
   361  //
   362  //	slice := g.Slice[int]{1, 2, 3, 4, 5}
   363  //	slice = slice.AddUnique(3, 4, 5, 6, 7)
   364  //	fmt.Println(slice)
   365  //
   366  // Output: [1 2 3 4 5 6 7].
   367  func (sl Slice[T]) AddUnique(elems ...T) Slice[T] {
   368  	for _, elem := range elems {
   369  		if !sl.Contains(elem) {
   370  			sl = append(sl, elem)
   371  		}
   372  	}
   373  
   374  	return sl
   375  }
   376  
   377  // AddUniqueInPlace appends unique elements from the provided arguments to the current slice.
   378  //
   379  // The function iterates over the provided elements and checks if they are already present
   380  // in the slice. If an element is not already present, it is appended to the slice.
   381  //
   382  // Parameters:
   383  //
   384  // - elems (...T): A variadic list of elements to be appended to the slice.
   385  //
   386  // Example usage:
   387  //
   388  //	slice := g.Slice[int]{1, 2, 3, 4, 5}
   389  //	slice.AddUniqueInPlace(3, 4, 5, 6, 7)
   390  //	fmt.Println(slice)
   391  //
   392  // Output: [1 2 3 4 5 6 7].
   393  func (sl *Slice[T]) AddUniqueInPlace(elems ...T) {
   394  	for _, elem := range elems {
   395  		if !sl.Contains(elem) {
   396  			*sl = append(*sl, elem)
   397  		}
   398  	}
   399  }
   400  
   401  // Get returns the element at the given index, handling negative indices as counting from the end
   402  // of the slice.
   403  func (sl Slice[T]) Get(index Int) T { return sl[sl.bound(index)] }
   404  
   405  // Shuffle shuffles the elements in the slice randomly.
   406  // This method modifies the original slice in place.
   407  //
   408  // The function uses the crypto/rand package to generate random indices.
   409  //
   410  // Example usage:
   411  //
   412  // slice := g.Slice[int]{1, 2, 3, 4, 5}
   413  // slice.Shuffle()
   414  // fmt.Println(slice)
   415  //
   416  // Output: A randomly shuffled version of the original slice, e.g., [4 1 5 2 3].
   417  func (sl Slice[T]) Shuffle() {
   418  	n := sl.Len()
   419  
   420  	for i := n - 1; i > 0; i-- {
   421  		j := rand.N(i + 1)
   422  		sl.swap(i, j)
   423  	}
   424  }
   425  
   426  // Reverse reverses the order of the elements in the slice.
   427  // This method modifies the original slice in place.
   428  //
   429  // Returns:
   430  //
   431  // - Slice[T]: The modified slice with the elements reversed.
   432  //
   433  // Example usage:
   434  //
   435  // slice := g.Slice[int]{1, 2, 3, 4, 5}
   436  // slice.Reverse()
   437  // fmt.Println(slice)
   438  //
   439  // Output: [5 4 3 2 1].
   440  func (sl Slice[T]) Reverse() { slices.Reverse(sl) }
   441  
   442  // SortBy sorts the elements in the slice using the provided comparison function.
   443  // It modifies the original slice in place. It requires the elements to be of a type
   444  // that is comparable.
   445  //
   446  // The function takes a custom comparison function as an argument and sorts the elements
   447  // of the slice using the provided logic. The comparison function should return true if
   448  // the element at index i should come before the element at index j, and false otherwise.
   449  //
   450  // Parameters:
   451  //
   452  // - f func(a, b T) cmp.Ordered: A comparison function that takes two indices i and j and returns a bool.
   453  //
   454  // Example usage:
   455  //
   456  // sl := NewSlice[int](1, 5, 3, 2, 4)
   457  // sl.SortBy(func(a, b int) cmp.Ordering { return cmp.Cmp(a, b) }) // sorts in ascending order.
   458  func (sl Slice[T]) SortBy(fn func(a, b T) cmp.Ordering) {
   459  	slices.SortFunc(sl, func(a, b T) int { return int(fn(a, b)) })
   460  }
   461  
   462  // ToStringSlice converts the Slice into a slice of strings.
   463  func (sl Slice[T]) ToStringSlice() []string {
   464  	result := make([]string, 0, len(sl))
   465  
   466  	for _, v := range sl {
   467  		result = append(result, fmt.Sprint(v))
   468  	}
   469  
   470  	return result
   471  }
   472  
   473  // Join joins the elements in the slice into a single String, separated by the provided separator
   474  // (if any).
   475  func (sl Slice[T]) Join(sep ...T) String {
   476  	var separator string
   477  	if len(sep) != 0 {
   478  		separator = fmt.Sprint(sep[0])
   479  	}
   480  
   481  	return String(strings.Join(sl.ToStringSlice(), separator))
   482  }
   483  
   484  // SubSlice returns a new slice containing elements from the current slice between the specified start
   485  // and end indices, with an optional step parameter to define the increment between elements.
   486  // The function checks if the start and end indices are within the bounds of the original slice.
   487  // If the end index is negative, it represents the position from the end of the slice.
   488  // If the start index is negative, it represents the position from the end of the slice counted
   489  // from the start index.
   490  //
   491  // Parameters:
   492  //
   493  // - start (Int): The start index of the range.
   494  //
   495  // - end (Int): The end index of the range.
   496  //
   497  // - step (Int, optional): The increment between elements. Defaults to 1 if not provided.
   498  // If negative, the slice is traversed in reverse order.
   499  //
   500  // Returns:
   501  //
   502  // - Slice[T]: A new slice containing elements from the current slice between the start and end
   503  // indices, with the specified step.
   504  //
   505  // Example usage:
   506  //
   507  //	slice := g.Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9}
   508  //	subSlice := slice.SubSlice(1, 7, 2) // Extracts elements 2, 4, 6
   509  //	fmt.Println(subSlice)
   510  //
   511  // Output: [2 4 6].
   512  func (sl Slice[T]) SubSlice(start, end Int, step ...Int) Slice[T] {
   513  	_step := Int(1)
   514  
   515  	if len(step) != 0 {
   516  		_step = step[0]
   517  	}
   518  
   519  	start = sl.bound(start, struct{}{})
   520  	end = sl.bound(end, struct{}{})
   521  
   522  	if (start >= end && _step > 0) || (start <= end && _step < 0) || _step == 0 {
   523  		return NewSlice[T]()
   524  	}
   525  
   526  	var loopCondition func(Int) bool
   527  	if _step > 0 {
   528  		loopCondition = func(i Int) bool { return i < end }
   529  	} else {
   530  		loopCondition = func(i Int) bool { return i > end }
   531  	}
   532  
   533  	var slice Slice[T]
   534  
   535  	for i := start; loopCondition(i); i += _step {
   536  		slice = append(slice, sl[i])
   537  	}
   538  
   539  	return slice
   540  }
   541  
   542  // Cut removes a range of elements from the Slice and returns a new Slice.
   543  // It creates two slices: one from the beginning of the original slice up to
   544  // the specified start index (exclusive), and another from the specified end
   545  // index (inclusive) to the end of the original slice. These two slices are
   546  // then concatenated to form the resulting Slice.
   547  //
   548  // Parameters:
   549  //
   550  // - start (Int): The start index of the range to be removed.
   551  //
   552  // - end (Int): The end index of the range to be removed.
   553  //
   554  // Note:
   555  //
   556  //	The function also supports negative indices. Negative indices are counted
   557  //	from the end of the slice. For example, -1 means the last element, -2
   558  //	means the second-to-last element, and so on.
   559  //
   560  // Returns:
   561  //
   562  //	Slice[T]: A new slice containing elements from the current slice with
   563  //	the specified range removed.
   564  //
   565  // Example:
   566  //
   567  //	slice := g.Slice[int]{1, 2, 3, 4, 5}
   568  //	newSlice := slice.Cut(1, 3)
   569  //	// newSlice is [1 4 5]
   570  func (sl Slice[T]) Cut(start, end Int) Slice[T] { return sl.Replace(start, end) }
   571  
   572  // CutInPlace removes a range of elements from the Slice in-place.
   573  // It modifies the original slice by creating two slices: one from the
   574  // beginning of the original slice up to the specified start index
   575  // (exclusive), and another from the specified end index (inclusive)
   576  // to the end of the original slice. These two slices are then
   577  // concatenated to form the modified original Slice.
   578  //
   579  // Parameters:
   580  //
   581  // - start (Int): The start index of the range to be removed.
   582  //
   583  // - end (Int): The end index of the range to be removed.
   584  //
   585  // Note:
   586  //
   587  // The function also supports negative indices. Negative indices are counted
   588  // from the end of the slice. For example, -1 means the last element, -2
   589  // means the second-to-last element, and so on.
   590  func (sl *Slice[T]) CutInPlace(start, end Int) { sl.ReplaceInPlace(start, end) }
   591  
   592  // Random returns a random element from the slice.
   593  //
   594  // The function uses the crypto/rand package to generate a random index within the bounds of the
   595  // slice. If the slice is empty, the zero value of type T is returned.
   596  //
   597  // Returns:
   598  //
   599  // - T: A random element from the slice.
   600  //
   601  // Example usage:
   602  //
   603  //	slice := g.Slice[int]{1, 2, 3, 4, 5}
   604  //	randomElement := slice.Random()
   605  //	fmt.Println(randomElement)
   606  //
   607  // Output: <any random element from the slice>.
   608  func (sl Slice[T]) Random() T {
   609  	if sl.Empty() {
   610  		return *new(T)
   611  	}
   612  
   613  	return sl[rand.N(sl.Len())]
   614  }
   615  
   616  // Clone returns a copy of the slice.
   617  func (sl Slice[T]) Clone() Slice[T] { return slices.Clone(sl) }
   618  
   619  // LastIndex returns the last index of the slice.
   620  func (sl Slice[T]) LastIndex() Int {
   621  	if sl.NotEmpty() {
   622  		return sl.Len() - 1
   623  	}
   624  
   625  	return 0
   626  }
   627  
   628  // Eq returns true if the slice is equal to the provided other slice.
   629  func (sl Slice[T]) Eq(other Slice[T]) bool {
   630  	switch o := any(other).(type) {
   631  	case Slice[Int]:
   632  		return slices.Equal(any(sl).(Slice[Int]), o)
   633  	case Slice[String]:
   634  		return slices.Equal(any(sl).(Slice[String]), o)
   635  	case Slice[Float]:
   636  		return slices.Equal(any(sl).(Slice[Float]), o)
   637  	case Slice[int]:
   638  		return slices.Equal(any(sl).(Slice[int]), o)
   639  	case Slice[string]:
   640  		return slices.Equal(any(sl).(Slice[string]), o)
   641  	case Slice[bool]:
   642  		return slices.Equal(any(sl).(Slice[bool]), o)
   643  	case Slice[int8]:
   644  		return slices.Equal(any(sl).(Slice[int8]), o)
   645  	case Slice[int16]:
   646  		return slices.Equal(any(sl).(Slice[int16]), o)
   647  	case Slice[int32]:
   648  		return slices.Equal(any(sl).(Slice[int32]), o)
   649  	case Slice[int64]:
   650  		return slices.Equal(any(sl).(Slice[int64]), o)
   651  	case Slice[uint]:
   652  		return slices.Equal(any(sl).(Slice[uint]), o)
   653  	case Slice[uint8]:
   654  		return slices.Equal(any(sl).(Slice[uint8]), o)
   655  	case Slice[uint16]:
   656  		return slices.Equal(any(sl).(Slice[uint16]), o)
   657  	case Slice[uint32]:
   658  		return slices.Equal(any(sl).(Slice[uint32]), o)
   659  	case Slice[uint64]:
   660  		return slices.Equal(any(sl).(Slice[uint64]), o)
   661  	case Slice[float32]:
   662  		return slices.Equal(any(sl).(Slice[float32]), o)
   663  	case Slice[float64]:
   664  		return slices.Equal(any(sl).(Slice[float64]), o)
   665  	default:
   666  		return sl.EqBy(other, func(x, y T) bool { return reflect.DeepEqual(x, y) })
   667  	}
   668  }
   669  
   670  // EqBy reports whether two slices are equal using an equality
   671  // function on each pair of elements. If the lengths are different,
   672  // EqBy returns false. Otherwise, the elements are compared in
   673  // increasing index order, and the comparison stops at the first index
   674  // for which eq returns false.
   675  func (sl Slice[T]) EqBy(other Slice[T], fn func(x, y T) bool) bool {
   676  	return slices.EqualFunc(sl, other, fn)
   677  }
   678  
   679  // String returns a string representation of the slice.
   680  func (sl Slice[T]) String() string {
   681  	builder := NewBuilder()
   682  
   683  	for _, v := range sl {
   684  		builder.Write(Sprintf("%v, ", v))
   685  	}
   686  
   687  	return builder.String().TrimRight(", ").Format("Slice[%s]").Std()
   688  }
   689  
   690  // Append appends the provided elements to the slice and returns the modified slice.
   691  func (sl Slice[T]) Append(elems ...T) Slice[T] { return append(sl, elems...) }
   692  
   693  // AppendInPlace appends the provided elements to the slice and modifies the original slice.
   694  func (sl *Slice[T]) AppendInPlace(elems ...T) { *sl = append(*sl, elems...) }
   695  
   696  // Cap returns the capacity of the Slice.
   697  func (sl Slice[T]) Cap() Int { return Int(cap(sl)) }
   698  
   699  // Contains returns true if the slice contains the provided value.
   700  func (sl Slice[T]) Contains(val T) bool { return sl.Index(val) >= 0 }
   701  
   702  // ContainsBy returns true if the slice contains an element that satisfies the provided function fn, false otherwise.
   703  func (sl Slice[T]) ContainsBy(fn func(t T) bool) bool { return sl.IndexBy(fn) >= 0 }
   704  
   705  // ContainsAny checks if the Slice contains any element from another Slice.
   706  func (sl Slice[T]) ContainsAny(values ...T) bool {
   707  	if sl.Empty() || len(values) == 0 {
   708  		return false
   709  	}
   710  
   711  	for _, v := range values {
   712  		if sl.Contains(v) {
   713  			return true
   714  		}
   715  	}
   716  
   717  	return false
   718  }
   719  
   720  // ContainsAll checks if the Slice contains all elements from another Slice.
   721  func (sl Slice[T]) ContainsAll(values ...T) bool {
   722  	if sl.Empty() || len(values) == 0 {
   723  		return false
   724  	}
   725  
   726  	for _, v := range values {
   727  		if !sl.Contains(v) {
   728  			return false
   729  		}
   730  	}
   731  
   732  	return true
   733  }
   734  
   735  // Delete removes the element at the specified index from the slice and returns the modified slice.
   736  func (sl Slice[T]) Delete(i Int) Slice[T] {
   737  	nsl := sl.Clone()
   738  	nsl.DeleteInPlace(i)
   739  
   740  	return nsl.Clip()
   741  }
   742  
   743  // DeleteInPlace removes the element at the specified index from the slice and modifies the
   744  // original slice.
   745  func (sl *Slice[T]) DeleteInPlace(i Int) {
   746  	i = sl.bound(i)
   747  	copy((*sl)[i:], (*sl)[i+1:])
   748  	*sl = (*sl)[:len(*sl)-1]
   749  }
   750  
   751  // Empty returns true if the slice is empty.
   752  func (sl Slice[T]) Empty() bool { return len(sl) == 0 }
   753  
   754  // Last returns the last element of the slice.
   755  func (sl Slice[T]) Last() T { return sl.Get(-1) }
   756  
   757  // Ne returns true if the slice is not equal to the provided other slice.
   758  func (sl Slice[T]) Ne(other Slice[T]) bool { return !sl.Eq(other) }
   759  
   760  // NeBy reports whether two slices are not equal using an inequality
   761  // function on each pair of elements. If the lengths are different,
   762  // NeBy returns true. Otherwise, the elements are compared in
   763  // increasing index order, and the comparison stops at the first index
   764  // for which fn returns true.
   765  func (sl Slice[T]) NeBy(other Slice[T], fn func(x, y T) bool) bool { return !sl.EqBy(other, fn) }
   766  
   767  // NotEmpty returns true if the slice is not empty.
   768  func (sl Slice[T]) NotEmpty() bool { return !sl.Empty() }
   769  
   770  // Pop returns the last element of the slice and a new slice without the last element.
   771  func (sl Slice[T]) Pop() (T, Slice[T]) { return sl.Last(), sl.SubSlice(0, -1) }
   772  
   773  // Set sets the value at the specified index in the slice and returns the modified slice.
   774  // This method modifies the original slice in place.
   775  //
   776  // Parameters:
   777  //
   778  // - index (Int): The index at which to set the new value.
   779  //
   780  // - val (T): The new value to be set at the specified index.
   781  //
   782  // Returns:
   783  //
   784  // - Slice[T]: The modified slice with the new value set at the specified index.
   785  //
   786  // Example usage:
   787  //
   788  // slice := g.Slice[int]{1, 2, 3, 4, 5}
   789  // slice.Set(2, 99)
   790  // fmt.Println(slice)
   791  //
   792  // Output: [1 2 99 4 5].
   793  func (sl Slice[T]) Set(index Int, val T) { sl[sl.bound(index)] = val }
   794  
   795  // Len returns the length of the slice.
   796  func (sl Slice[T]) Len() Int { return Int(len(sl)) }
   797  
   798  // Swap swaps the elements at the specified indices in the slice.
   799  // This method modifies the original slice in place.
   800  //
   801  // Parameters:
   802  //
   803  // - i (Int): The index of the first element to be swapped.
   804  //
   805  // - j (Int): The index of the second element to be swapped.
   806  //
   807  // Returns:
   808  //
   809  // - Slice[T]: The modified slice with the elements at the specified indices swapped.
   810  //
   811  // Example usage:
   812  //
   813  // slice := g.Slice[int]{1, 2, 3, 4, 5}
   814  // slice.Swap(1, 3)
   815  // fmt.Println(slice)
   816  //
   817  // Output: [1 4 3 2 5].
   818  func (sl Slice[T]) Swap(i, j Int) {
   819  	i = sl.bound(i)
   820  	j = sl.bound(j)
   821  
   822  	sl.swap(i, j)
   823  }
   824  
   825  func (sl Slice[T]) swap(i, j Int) { sl[i], sl[j] = sl[j], sl[i] }
   826  
   827  // Grow increases the slice's capacity, if necessary, to guarantee space for
   828  // another n elements. After Grow(n), at least n elements can be appended
   829  // to the slice without another allocation. If n is negative or too large to
   830  // allocate the memory, Grow panics.
   831  func (sl Slice[T]) Grow(n Int) Slice[T] { return slices.Grow(sl, n.Std()) }
   832  
   833  // Clip removes unused capacity from the slice.
   834  func (sl Slice[T]) Clip() Slice[T] { return slices.Clip(sl) }
   835  
   836  // Std returns a new slice with the same elements as the Slice[T].
   837  func (sl Slice[T]) Std() []T { return sl }
   838  
   839  // Print prints the elements of the Slice to the standard output (console)
   840  // and returns the Slice unchanged.
   841  func (sl Slice[T]) Print() Slice[T] { fmt.Println(sl); return sl }
   842  
   843  // Unpack assigns values of the slice's elements to the variables passed as pointers.
   844  // If the number of variables passed is greater than the length of the slice,
   845  // the function ignores the extra variables.
   846  //
   847  // Parameters:
   848  //
   849  // - vars (...*T): Pointers to variables where the values of the slice's elements will be stored.
   850  //
   851  // Example:
   852  //
   853  //	slice := g.Slice[int]{1, 2, 3, 4, 5}
   854  //	var a, b, c int
   855  //	slice.Unpack(&a, &b, &c)
   856  //	fmt.Println(a, b, c) // Output: 1 2 3
   857  func (sl Slice[T]) Unpack(vars ...*T) {
   858  	if len(vars) > len(sl) {
   859  		vars = vars[:len(sl)]
   860  	}
   861  
   862  	for i, v := range vars {
   863  		*v = sl[i]
   864  	}
   865  }
   866  
   867  // MaxBy returns the maximum value in the slice according to the provided comparison function fn.
   868  // It applies fn pairwise to the elements of the slice until it finds the maximum value.
   869  // It returns the maximum value found.
   870  //
   871  // Example:
   872  //
   873  //	s := Slice[int]{3, 1, 4, 2, 5}
   874  //	maxInt := s.MaxBy(cmp.Cmp)
   875  //	fmt.Println(maxInt) // Output: 5
   876  func (sl Slice[T]) MaxBy(fn func(a, b T) cmp.Ordering) T { return cmp.MaxBy(fn, sl...) }
   877  
   878  // MinBy returns the minimum value in the slice according to the provided comparison function fn.
   879  // It applies fn pairwise to the elements of the slice until it finds the minimum value.
   880  // It returns the minimum value found.
   881  //
   882  // Example:
   883  //
   884  //	s := Slice[int]{3, 1, 4, 2, 5}
   885  //	minInt := s.MinBy(cmp.Cmp)
   886  //	fmt.Println(minInt) // Output: 1
   887  func (sl Slice[T]) MinBy(fn func(a, b T) cmp.Ordering) T { return cmp.MinBy(fn, sl...) }
   888  
   889  func (sl Slice[T]) bound(i Int, subslice ...struct{}) Int {
   890  	ii := i
   891  	if ii < 0 {
   892  		ii += sl.Len()
   893  	}
   894  
   895  	var negative Int
   896  	if len(subslice) != 0 {
   897  		negative = -1
   898  	}
   899  
   900  	if ii > sl.Len() || ii < negative {
   901  		panic(fmt.Sprintf("runtime error: slice bounds out of range [%d] with length %d", i, len(sl)))
   902  	}
   903  
   904  	return ii
   905  }