• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

enetx / g / 14661178371

25 Apr 2025 09:14AM UTC coverage: 86.248% (-0.2%) from 86.478%
14661178371

push

github

enetx
ref

124 of 174 new or added lines in 13 files covered. (71.26%)

1 existing line in 1 file now uncovered.

3462 of 4014 relevant lines covered (86.25%)

127.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.03
/slice.go
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] {
124✔
36
        var (
124✔
37
                length   Int
124✔
38
                capacity Int
124✔
39
        )
124✔
40

124✔
41
        switch {
124✔
42
        case len(size) > 1:
4✔
43
                length, capacity = size[0], size[1]
4✔
44
        case len(size) == 1:
90✔
45
                length, capacity = size[0], size[0]
90✔
46
        }
47

48
        return make(Slice[T], length, capacity)
124✔
49
}
50

51
// TransformSlice applies the given function to each element of a Slice and returns a new Slice
52
// containing the transformed values.
53
//
54
// Parameters:
55
//
56
// - sl: The input Slice.
57
//
58
// - fn: The function to apply to each element of the input Slice.
59
//
60
// Returns:
61
//
62
// A new Slice containing the results of applying the function to each element of the input Slice.
63
func TransformSlice[T, U any](sl Slice[T], fn func(T) U) Slice[U] {
42✔
64
        return transformSlice(sl.Iter(), fn).Collect()
42✔
65
}
42✔
66

67
// SliceOf creates a new generic slice containing the provided elements.
68
func SliceOf[T any](slice ...T) Slice[T] { return slice }
70✔
69

70
// Ptr returns a pointer to the current Slice value.
71
func (sl Slice[T]) Ptr() *Slice[T] { return &sl }
1✔
72

73
// Transform applies a transformation function to the Slice and returns the result.
74
func (sl Slice[T]) Transform(fn func(Slice[T]) Slice[T]) Slice[T] { return fn(sl) }
2✔
75

76
// Iter returns an iterator (SeqSlice[T]) for the Slice, allowing for sequential iteration
77
// over its elements. It is commonly used in combination with higher-order functions,
78
// such as 'ForEach', to perform operations on each element of the Slice.
79
//
80
// Returns:
81
//
82
// A SeqSlice[T], which can be used for sequential iteration over the elements of the Slice.
83
//
84
// Example usage:
85
//
86
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
87
//        iterator := slice.Iter()
88
//        iterator.ForEach(func(element int) {
89
//                // Perform some operation on each element
90
//                fmt.Println(element)
91
//        })
92
//
93
// The 'Iter' method provides a convenient way to traverse the elements of a Slice
94
// in a functional style, enabling operations like mapping or filtering.
95
func (sl Slice[T]) Iter() SeqSlice[T] { return seqSlice(sl) }
159✔
96

97
// IntoIter returns a consuming iterator (SeqSlice[T]) for the Slice,
98
// transferring ownership of its elements and clearing the original Slice.
99
//
100
// This method is useful when you no longer need access to the original Slice
101
// and want to process its elements in a functional, sequential manner.
102
// After calling IntoIter, the original Slice is emptied and should not be reused
103
// unless reassigned.
104
//
105
// Returns:
106
//
107
// A SeqSlice[T] that yields the elements of the Slice and consumes them in the process.
108
//
109
// Example usage:
110
//
111
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
112
//        iterator := slice.IntoIter()
113
//        result := iterator.Map(func(x int) int {
114
//                return x * 2
115
//        }).Collect()
116
//        slice.Println() // Output: Slice[]
117
//
118
// The 'IntoIter' method enables ownership-like semantics, allowing
119
// iteration with transformation while invalidating the original Slice.
120
func (sl *Slice[T]) IntoIter() SeqSlice[T] {
1✔
121
        data := *sl
1✔
122
        *sl = nil
1✔
123

1✔
124
        return seqSlice(data)
1✔
125
}
1✔
126

127
// IterReverse returns an iterator (SeqSlice[T]) for the Slice that allows for sequential iteration
128
// over its elements in reverse order. This method is useful when you need to traverse the elements
129
// from the end to the beginning.
130
//
131
// Returns:
132
//
133
// A SeqSlice[T], which can be used for sequential iteration over the elements of the Slice in reverse order.
134
//
135
// Example usage:
136
//
137
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
138
//        iterator := slice.IterReverse()
139
//        iterator.ForEach(func(element int) {
140
//                // Perform some operation on each element in reverse order
141
//                fmt.Println(element)
142
//        })
143
//
144
// The 'IterReverse' method enhances the functionality of the Slice by providing an alternative
145
// way to iterate through its elements, enhancing flexibility in how data within a Slice is accessed and manipulated.
146
func (sl Slice[T]) IterReverse() SeqSlice[T] { return revSeqSlice(sl) }
3✔
147

148
// AsAny converts each element of the slice to the 'any' type.
149
// It returns a new slice containing the elements as 'any' g.Slice[any].
150
//
151
// Note: AsAny is useful when you want to work with a slice of a specific type as a slice of 'any'.
152
// It can be particularly handy in conjunction with Flatten to work with nested slices of different types.
153
func (sl Slice[T]) AsAny() Slice[any] { return TransformSlice(sl, func(t T) any { return any(t) }) }
12✔
154

155
// Fill fills the slice with the specified value.
156
// This function is useful when you want to create an Slice with all elements having the same
157
// value.
158
// This method modifies the original slice in place.
159
//
160
// Parameters:
161
//
162
// - val T: The value to fill the Slice with.
163
//
164
// Returns:
165
//
166
// - Slice[T]: A reference to the original Slice filled with the specified value.
167
//
168
// Example usage:
169
//
170
//        slice := g.Slice[int]{0, 0, 0}
171
//        slice.Fill(5)
172
//
173
// The modified slice will now contain: 5, 5, 5.
174
func (sl Slice[T]) Fill(val T) {
1✔
175
        for i := range sl {
6✔
176
                sl[i] = val
5✔
177
        }
5✔
178
}
179

180
// Index returns the index of the first occurrence of the specified value in the slice, or -1 if
181
// not found.
182
func (sl Slice[T]) Index(val T) Int {
99✔
183
        switch s := any(sl).(type) {
99✔
184
        case Slice[Int]:
1✔
185
                return Int(slices.Index(s, any(val).(Int)))
1✔
186
        case Slice[String]:
1✔
187
                return Int(slices.Index(s, any(val).(String)))
1✔
188
        case Slice[Float]:
1✔
189
                return Int(slices.Index(s, any(val).(Float)))
1✔
190
        case Slice[string]:
7✔
191
                return Int(slices.Index(s, any(val).(string)))
7✔
192
        case Slice[bool]:
1✔
193
                return Int(slices.Index(s, any(val).(bool)))
1✔
194
        case Slice[int]:
69✔
195
                return Int(slices.Index(s, any(val).(int)))
69✔
196
        case Slice[int8]:
1✔
197
                return Int(slices.Index(s, any(val).(int8)))
1✔
198
        case Slice[int16]:
1✔
199
                return Int(Int(slices.Index(s, any(val).(int16))))
1✔
200
        case Slice[int32]:
1✔
201
                return Int(slices.Index(s, any(val).(int32)))
1✔
202
        case Slice[int64]:
1✔
203
                return Int(slices.Index(s, any(val).(int64)))
1✔
204
        case Slice[uint]:
1✔
205
                return Int(slices.Index(s, any(val).(uint)))
1✔
206
        case Slice[uint8]:
2✔
207
                return Int(slices.Index(s, any(val).(uint8)))
2✔
208
        case Slice[uint16]:
1✔
209
                return Int(slices.Index(s, any(val).(uint16)))
1✔
210
        case Slice[uint32]:
1✔
211
                return Int(slices.Index(s, any(val).(uint32)))
1✔
212
        case Slice[uint64]:
1✔
213
                return Int(slices.Index(s, any(val).(uint64)))
1✔
214
        case Slice[float32]:
1✔
215
                return Int(slices.Index(s, any(val).(float32)))
1✔
216
        case Slice[float64]:
6✔
217
                return Int(slices.Index(s, any(val).(float64)))
6✔
218
        default:
2✔
219
                return sl.IndexBy(f.Eqd(val))
2✔
220
        }
221
}
222

223
// IndexBy returns the index of the first element in the slice
224
// satisfying the custom comparison function provided by the user.
225
// It iterates through the slice and applies the comparison function to each element and the target value.
226
// If the comparison function returns true for any pair of elements, it returns the index of that element.
227
// If no such element is found, it returns -1.
228
func (sl Slice[T]) IndexBy(fn func(t T) bool) Int { return Int(slices.IndexFunc(sl, fn)) }
8✔
229

230
// RandomSample returns a new slice containing a random sample of elements from the original slice.
231
// The sampling is done without replacement, meaning that each element can only appear once in the result.
232
//
233
// Parameters:
234
//
235
// - sequence int: The number of unique elements to include in the random sample.
236
//
237
// Returns:
238
//
239
// - Slice[T]: A new Slice containing the random sample of unique elements.
240
//
241
// Example usage:
242
//
243
//        slice := g.Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9}
244
//        sample := slice.RandomSample(3)
245
//
246
// The resulting sample will contain 3 unique elements randomly selected from the original slice.
247
func (sl Slice[T]) RandomSample(sequence Int) Slice[T] {
1✔
248
        if sequence.Gte(sl.Len()) {
1✔
249
                return sl
×
250
        }
×
251

252
        clone := sl.Clone()
1✔
253
        clone.Shuffle()
1✔
254

1✔
255
        return clone[0:sequence]
1✔
256
}
257

258
// RandomRange returns a new slice containing a random sample of elements from a subrange of the original slice.
259
// The sampling is done without replacement, meaning that each element can only appear once in the result.
260
func (sl Slice[T]) RandomRange(from, to Int) Slice[T] {
×
261
        if from < 0 {
×
262
                from = 0
×
263
        }
×
264

265
        if to < 0 || to > sl.Len() {
×
266
                to = sl.Len()
×
267
        }
×
268

269
        if from > to {
×
270
                from = to
×
271
        }
×
272

273
        return sl.RandomSample(from.RandomRange(to))
×
274
}
275

276
// Insert inserts values at the specified index in the slice and modifies the original
277
// slice.
278
//
279
// Parameters:
280
//
281
// - i Int: The index at which to insert the new values.
282
//
283
// - values ...T: A variadic list of values to insert at the specified index.
284
//
285
// Example usage:
286
//
287
//        slice := g.Slice[string]{"a", "b", "c", "d"}
288
//        slice.Insert(2, "e", "f")
289
//
290
// The resulting slice will be: ["a", "b", "e", "f", "c", "d"].
291
func (sl *Slice[T]) Insert(i Int, values ...T) {
18✔
292
        if sl.Empty() {
19✔
293
                if i != 0 {
1✔
NEW
294
                        panic(Errorf("runtime error: slice bounds out of range [{}] with length 0", i))
×
295
                }
296

297
                sl.Push(values...)
1✔
298
                return
1✔
299
        }
300

301
        sl.Replace(i, i, values...)
17✔
302
}
303

304
// Replace replaces the elements of sl[i:j] with the given values,
305
// and modifies the original slice in place. Replace panics if sl[i:j]
306
// is not a valid slice of sl.
307
//
308
// Parameters:
309
//
310
// - i int: The starting index of the slice to be replaced.
311
//
312
// - j int: The ending index of the slice to be replaced.
313
//
314
// - values ...T: A variadic list of values to replace the existing slice.
315
//
316
// Example usage:
317
//
318
//        slice := g.Slice[string]{"a", "b", "c", "d"}
319
//        slice.Replace(1, 3, "e", "f")
320
//
321
// After the Replace operation, the resulting slice will be: ["a", "e", "f", "d"].
322
func (sl *Slice[T]) Replace(i, j Int, values ...T) {
28✔
323
        ii := sl.bound(i)
28✔
324
        jj := sl.bound(j)
28✔
325

28✔
326
        if ii.IsErr() {
28✔
NEW
327
                panic(ii.Err())
×
328
        }
329

330
        if jj.IsErr() {
28✔
NEW
331
                panic(jj.Err())
×
332
        }
333

334
        i, j = ii.Ok(), jj.Ok()
28✔
335

28✔
336
        if i > j {
28✔
337
                *sl = (*sl)[:0]
×
338
                return
×
339
        }
×
340

341
        if i == j {
45✔
342
                if len(values) > 0 {
34✔
343
                        *sl = append((*sl)[:i], append(values, (*sl)[i:]...)...)
17✔
344
                }
17✔
345

346
                return
17✔
347
        }
348

349
        diff := Int(len(values)) - (j - i)
11✔
350

11✔
351
        if diff > 0 {
12✔
352
                *sl = append(*sl, NewSlice[T](diff)...)
1✔
353
        }
1✔
354

355
        copy((*sl)[i+Int(len(values)):], (*sl)[j:])
11✔
356
        copy((*sl)[i:], values)
11✔
357

11✔
358
        if diff < 0 {
17✔
359
                *sl = (*sl)[:(*sl).Len()+diff]
6✔
360
        }
6✔
361
}
362

363
// Get returns the element at the given index, handling negative indices as counting from the end
364
// of the slice.
365
func (sl Slice[T]) Get(index Int) Option[T] {
385✔
366
        i := sl.bound(index)
385✔
367
        if i.IsErr() {
633✔
368
                return None[T]()
248✔
369
        }
248✔
370

371
        return Some(sl[i.Ok()])
137✔
372
}
373

374
// Shuffle shuffles the elements in the slice randomly.
375
// This method modifies the original slice in place.
376
//
377
// The function uses the crypto/rand package to generate random indices.
378
//
379
// Example usage:
380
//
381
// slice := g.Slice[int]{1, 2, 3, 4, 5}
382
// slice.Shuffle()
383
// fmt.Println(slice)
384
//
385
// Output: A randomly shuffled version of the original slice, e.g., [4 1 5 2 3].
386
func (sl Slice[T]) Shuffle() {
2✔
387
        for i := sl.Len() - 1; i > 0; i-- {
20✔
388
                j := rand.N(i + 1)
18✔
389
                sl.swap(i, j)
18✔
390
        }
18✔
391
}
392

393
// Reverse reverses the order of the elements in the slice.
394
// This method modifies the original slice in place.
395
//
396
// Returns:
397
//
398
// - Slice[T]: The modified slice with the elements reversed.
399
//
400
// Example usage:
401
//
402
// slice := g.Slice[int]{1, 2, 3, 4, 5}
403
// slice.Reverse()
404
// fmt.Println(slice)
405
//
406
// Output: [5 4 3 2 1].
407
func (sl Slice[T]) Reverse() { slices.Reverse(sl) }
1✔
408

409
// SortBy sorts the elements in the slice using the provided comparison function.
410
// It modifies the original slice in place. It requires the elements to be of a type
411
// that is comparable.
412
//
413
// The function takes a custom comparison function as an argument and sorts the elements
414
// of the slice using the provided logic. The comparison function should return true if
415
// the element at index i should come before the element at index j, and false otherwise.
416
//
417
// Parameters:
418
//
419
// - f func(a, b T) cmp.Ordered: A comparison function that takes two indices i and j and returns a bool.
420
//
421
// Example usage:
422
//
423
// sl := NewSlice[int](1, 5, 3, 2, 4)
424
// sl.SortBy(func(a, b int) cmp.Ordering { return cmp.Cmp(a, b) }) // sorts in ascending order.
425
func (sl Slice[T]) SortBy(fn func(a, b T) cmp.Ordering) {
7✔
426
        slices.SortFunc(sl, func(a, b T) int { return int(fn(a, b)) })
27✔
427
}
428

429
// ToStringSlice converts the Slice into a slice of strings.
430
func (sl Slice[T]) ToStringSlice() []string {
31✔
431
        result := make([]string, 0, len(sl))
31✔
432

31✔
433
        for _, v := range sl {
113✔
434
                result = append(result, fmt.Sprint(v))
82✔
435
        }
82✔
436

437
        return result
31✔
438
}
439

440
// Join joins the elements in the slice into a single String, separated by the provided separator
441
// (if any).
442
func (sl Slice[T]) Join(sep ...T) String {
13✔
443
        var separator string
13✔
444
        if len(sep) != 0 {
19✔
445
                separator = fmt.Sprint(sep[0])
6✔
446
        }
6✔
447

448
        return String(strings.Join(sl.ToStringSlice(), separator))
13✔
449
}
450

451
// SubSlice returns a new slice containing elements from the current slice between the specified start
452
// and end indices, with an optional step parameter to define the increment between elements.
453
// The function checks if the start and end indices are within the bounds of the original slice.
454
// If the end index is negative, it represents the position from the end of the slice.
455
// If the start index is negative, it represents the position from the end of the slice counted
456
// from the start index.
457
//
458
// Parameters:
459
//
460
// - start (Int): The start index of the range.
461
//
462
// - end (Int): The end index of the range.
463
//
464
// - step (Int, optional): The increment between elements. Defaults to 1 if not provided.
465
// If negative, the slice is traversed in reverse order.
466
//
467
// Returns:
468
//
469
// - Slice[T]: A new slice containing elements from the current slice between the start and end
470
// indices, with the specified step.
471
//
472
// Example usage:
473
//
474
//        slice := g.Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9}
475
//        subSlice := slice.SubSlice(1, 7, 2) // Extracts elements 2, 4, 6
476
//        fmt.Println(subSlice)
477
//
478
// Output: [2 4 6].
479
func (sl Slice[T]) SubSlice(start, end Int, step ...Int) Slice[T] {
35✔
480
        if sl.Empty() {
36✔
481
                return sl
1✔
482
        }
1✔
483

484
        _step := Slice[Int](step).Get(0).UnwrapOr(1)
34✔
485

34✔
486
        ii := sl.bound(start, struct{}{})
34✔
487
        jj := sl.bound(end, struct{}{})
34✔
488

34✔
489
        if ii.IsErr() {
36✔
490
                panic(ii.Err())
2✔
491
        }
492

493
        if jj.IsErr() {
33✔
494
                panic(jj.Err())
1✔
495
        }
496

497
        start, end = ii.Ok(), jj.Ok()
31✔
498

31✔
499
        if (start >= end && _step > 0) || (start <= end && _step < 0) || _step == 0 {
34✔
500
                return NewSlice[T]()
3✔
501
        }
3✔
502

503
        var loopCondition func(Int) bool
28✔
504
        if _step > 0 {
45✔
505
                loopCondition = func(i Int) bool { return i < end }
102✔
506
        } else {
11✔
507
                loopCondition = func(i Int) bool { return i > end }
69✔
508
        }
509

510
        var slice Slice[T]
28✔
511

28✔
512
        for i := start; loopCondition(i); i += _step {
143✔
513
                slice = append(slice, sl[i])
115✔
514
        }
115✔
515

516
        return slice
28✔
517
}
518

519
// Random returns a random element from the slice.
520
//
521
// The function uses the crypto/rand package to generate a random index within the bounds of the
522
// slice. If the slice is empty, the zero value of type T is returned.
523
//
524
// Returns:
525
//
526
// - T: A random element from the slice.
527
//
528
// Example usage:
529
//
530
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
531
//        randomElement := slice.Random()
532
//        fmt.Println(randomElement)
533
//
534
// Output: <any random element from the slice>.
535
func (sl Slice[T]) Random() T {
12,236✔
536
        if sl.Empty() {
12,237✔
537
                return *new(T)
1✔
538
        }
1✔
539

540
        return sl[rand.N(sl.Len())]
12,235✔
541
}
542

543
// Clone returns a copy of the slice.
544
func (sl Slice[T]) Clone() Slice[T] { return slices.Clone(sl) }
2✔
545

546
// LastIndex returns the last index of the slice.
547
func (sl Slice[T]) LastIndex() Int {
2✔
548
        if sl.NotEmpty() {
3✔
549
                return sl.Len() - 1
1✔
550
        }
1✔
551

552
        return 0
1✔
553
}
554

555
// Eq returns true if the slice is equal to the provided other slice.
556
func (sl Slice[T]) Eq(other Slice[T]) bool {
90✔
557
        switch o := any(other).(type) {
90✔
558
        case Slice[Int]:
1✔
559
                return slices.Equal(any(sl).(Slice[Int]), o)
1✔
560
        case Slice[String]:
3✔
561
                return slices.Equal(any(sl).(Slice[String]), o)
3✔
562
        case Slice[Float]:
2✔
563
                return slices.Equal(any(sl).(Slice[Float]), o)
2✔
564
        case Slice[int]:
50✔
565
                return slices.Equal(any(sl).(Slice[int]), o)
50✔
566
        case Slice[string]:
13✔
567
                return slices.Equal(any(sl).(Slice[string]), o)
13✔
568
        case Slice[bool]:
1✔
569
                return slices.Equal(any(sl).(Slice[bool]), o)
1✔
570
        case Slice[int8]:
1✔
571
                return slices.Equal(any(sl).(Slice[int8]), o)
1✔
572
        case Slice[int16]:
1✔
573
                return slices.Equal(any(sl).(Slice[int16]), o)
1✔
574
        case Slice[int32]:
1✔
575
                return slices.Equal(any(sl).(Slice[int32]), o)
1✔
576
        case Slice[int64]:
1✔
577
                return slices.Equal(any(sl).(Slice[int64]), o)
1✔
578
        case Slice[uint]:
1✔
579
                return slices.Equal(any(sl).(Slice[uint]), o)
1✔
580
        case Slice[uint8]:
2✔
581
                return slices.Equal(any(sl).(Slice[uint8]), o)
2✔
582
        case Slice[uint16]:
1✔
583
                return slices.Equal(any(sl).(Slice[uint16]), o)
1✔
584
        case Slice[uint32]:
1✔
585
                return slices.Equal(any(sl).(Slice[uint32]), o)
1✔
586
        case Slice[uint64]:
1✔
587
                return slices.Equal(any(sl).(Slice[uint64]), o)
1✔
588
        case Slice[float32]:
1✔
589
                return slices.Equal(any(sl).(Slice[float32]), o)
1✔
590
        case Slice[float64]:
2✔
591
                return slices.Equal(any(sl).(Slice[float64]), o)
2✔
592
        default:
7✔
593
                return sl.EqBy(other, func(x, y T) bool { return reflect.DeepEqual(x, y) })
23✔
594
        }
595
}
596

597
// EqBy reports whether two slices are equal using an equality
598
// function on each pair of elements. If the lengths are different,
599
// EqBy returns false. Otherwise, the elements are compared in
600
// increasing index order, and the comparison stops at the first index
601
// for which eq returns false.
602
func (sl Slice[T]) EqBy(other Slice[T], fn func(x, y T) bool) bool {
12✔
603
        return slices.EqualFunc(sl, other, fn)
12✔
604
}
12✔
605

606
// String returns a string representation of the slice.
607
func (sl Slice[T]) String() string {
1✔
608
        builder := NewBuilder()
1✔
609

1✔
610
        for _, v := range sl {
6✔
611
                builder.Write(Format("{}, ", v))
5✔
612
        }
5✔
613

614
        return builder.String().StripSuffix(", ").Format("Slice[{}]").Std()
1✔
615
}
616

617
// Append appends the provided elements to the slice and returns the modified slice.
618
func (sl Slice[T]) Append(elems ...T) Slice[T] { return append(sl, elems...) }
×
619

620
// Prepend prepends the provided elements to the slice and returns the modified slice.
621
func (sl Slice[T]) Prepend(elems ...T) Slice[T] { return append(elems, sl...) }
×
622

623
// AppendUnique appends unique elements from the provided arguments to the current slice.
624
//
625
// The function iterates over the provided elements and checks if they are already present
626
// in the slice. If an element is not already present, it is appended to the slice. The
627
// resulting slice is returned, containing the unique elements from both the original
628
// slice and the provided elements.
629
//
630
// Parameters:
631
//
632
// - elems (...T): A variadic list of elements to be appended to the slice.
633
//
634
// Returns:
635
//
636
// - Slice[T]: A new slice containing the unique elements from both the original slice
637
// and the provided elements.
638
//
639
// Example usage:
640
//
641
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
642
//        slice = slice.AppendUnique(3, 4, 5, 6, 7)
643
//        fmt.Println(slice)
644
//
645
// Output: [1 2 3 4 5 6 7].
646
func (sl Slice[T]) AppendUnique(elems ...T) Slice[T] {
×
647
        for _, elem := range elems {
×
648
                if !sl.Contains(elem) {
×
649
                        sl = append(sl, elem)
×
650
                }
×
651
        }
652

653
        return sl
×
654
}
655

656
// PrependUnique prepends unique elements from the provided arguments to the current slice.
657
//
658
// The function iterates over the provided elements and checks if they are already present
659
// in the slice. If an element is not already present, it is prepended to the beginning of the slice.
660
// The resulting slice is returned.
661
//
662
// Example:
663
//
664
//        slice := g.Slice[int]{3, 4, 5}
665
//        slice = slice.PrependUnique(1, 2, 3, 4)
666
//        fmt.Println(slice) // [1 2 3 4 5]
667
func (sl Slice[T]) PrependUnique(elems ...T) Slice[T] {
2✔
668
        var unique []T
2✔
669
        for _, elem := range elems {
9✔
670
                if !sl.Contains(elem) {
12✔
671
                        unique = append(unique, elem)
5✔
672
                }
5✔
673
        }
674
        return append(unique, sl...)
2✔
675
}
676

677
// Push appends the provided elements to the slice and modifies the original slice.
678
func (sl *Slice[T]) Push(elems ...T) { *sl = append(*sl, elems...) }
30✔
679

680
// PushFront inserts the provided elements at the beginning of the slice.
681
// It modifies the original slice in place.
682
//
683
// Example:
684
//
685
//        s := g.Slice[int]{3, 4, 5}
686
//        s.PushFront(1, 2)
687
//        fmt.Println(s) // [1 2 3 4 5]
688
func (sl *Slice[T]) PushFront(elems ...T) { *sl = append(elems, *sl...) }
3✔
689

690
// PushUnique appends unique elements from the provided arguments to the current slice.
691
//
692
// The function iterates over the provided elements and checks if they are already present
693
// in the slice. If an element is not already present, it is appended to the slice.
694
//
695
// Parameters:
696
//
697
// - elems (...T): A variadic list of elements to be appended to the slice.
698
//
699
// Example usage:
700
//
701
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
702
//        slice.PushUnique(3, 4, 5, 6, 7)
703
//        fmt.Println(slice)
704
//
705
// Output: [1 2 3 4 5 6 7].
706
func (sl *Slice[T]) PushUnique(elems ...T) {
3✔
707
        for _, elem := range elems {
16✔
708
                if !sl.Contains(elem) {
18✔
709
                        sl.Push(elem)
5✔
710
                }
5✔
711
        }
712
}
713

714
// PushFrontUnique prepends unique elements to the beginning of the slice in place.
715
//
716
// It modifies the current slice, adding only those elements that are not already present.
717
//
718
// Example:
719
//
720
//        slice := g.Slice[int]{3, 4, 5}
721
//        slice.PushFrontUnique(1, 2, 3, 4)
722
//        fmt.Println(slice) // [1 2 3 4 5]
723
func (sl *Slice[T]) PushFrontUnique(elems ...T) {
2✔
724
        var unique []T
2✔
725
        for _, elem := range elems {
9✔
726
                if !sl.Contains(elem) {
12✔
727
                        unique = append(unique, elem)
5✔
728
                }
5✔
729
        }
730

731
        if len(unique) > 0 {
4✔
732
                *sl = append(unique, *sl...)
2✔
733
        }
2✔
734
}
735

736
// Cap returns the capacity of the Slice.
737
func (sl Slice[T]) Cap() Int { return Int(cap(sl)) }
2✔
738

739
// Contains returns true if the slice contains the provided value.
740
func (sl Slice[T]) Contains(val T) bool { return sl.Index(val) >= 0 }
79✔
741

742
// ContainsBy returns true if the slice contains an element that satisfies the provided function fn, false otherwise.
743
func (sl Slice[T]) ContainsBy(fn func(t T) bool) bool { return sl.IndexBy(fn) >= 0 }
3✔
744

745
// ContainsAny checks if the Slice contains any element from another Slice.
746
func (sl Slice[T]) ContainsAny(values ...T) bool {
8✔
747
        if sl.Empty() || len(values) == 0 {
10✔
748
                return false
2✔
749
        }
2✔
750

751
        return slices.ContainsFunc(values, sl.Contains)
6✔
752
}
753

754
// ContainsAll checks if the Slice contains all elements from another Slice.
755
func (sl Slice[T]) ContainsAll(values ...T) bool {
8✔
756
        if sl.Empty() || len(values) == 0 {
10✔
757
                return false
2✔
758
        }
2✔
759

760
        for _, v := range values {
32✔
761
                if !sl.Contains(v) {
28✔
762
                        return false
2✔
763
                }
2✔
764
        }
765

766
        return true
4✔
767
}
768

769
// Delete removes an element or a range of elements from the Slice in-place.
770
// It modifies the original Slice by creating two slices: one from the
771
// beginning of the Slice up to the specified `start` index (exclusive),
772
// and another from the `end` index (inclusive) to the end of the Slice.
773
// These two slices are then concatenated to form the modified Slice.
774
//
775
// Parameters:
776
//
777
//   - start (Int): The starting index of the element or range to be removed.
778
//   - end (Int, optional): The end index of the range to be removed.
779
//     If omitted, only the element at the `start` index is removed.
780
//
781
// Note:
782
//
783
// The function supports negative indices. Negative values are counted from
784
// the end of the Slice: for example, -1 refers to the last element, -2 to
785
// the second-to-last, and so on.
786
func (sl *Slice[T]) Delete(start Int, end ...Int) {
5✔
787
        sl.Replace(start, Slice[Int](end).Get(0).UnwrapOr(start+1))
5✔
788
}
5✔
789

790
// Empty returns true if the slice is empty.
791
func (sl Slice[T]) Empty() bool { return len(sl) == 0 }
12,872✔
792

793
// Last returns the last element of the slice.
794
func (sl Slice[T]) Last() Option[T] { return sl.Get(-1) }
1✔
795

796
// Ne returns true if the slice is not equal to the provided other slice.
797
func (sl Slice[T]) Ne(other Slice[T]) bool { return !sl.Eq(other) }
11✔
798

799
// NeBy reports whether two slices are not equal using an inequality
800
// function on each pair of elements. If the lengths are different,
801
// NeBy returns true. Otherwise, the elements are compared in
802
// increasing index order, and the comparison stops at the first index
803
// for which fn returns true.
804
func (sl Slice[T]) NeBy(other Slice[T], fn func(x, y T) bool) bool { return !sl.EqBy(other, fn) }
2✔
805

806
// NotEmpty checks if the Slice is not empty.
807
func (sl Slice[T]) NotEmpty() bool { return !sl.Empty() }
4✔
808

809
// Pop removes and returns the last element of the slice.
810
// It mutates the original slice by removing the last element.
811
// It returns None if the slice is empty.
812
func (sl *Slice[T]) Pop() Option[T] {
2✔
813
        if sl.Len() == 0 {
2✔
NEW
814
                return None[T]()
×
NEW
815
        }
×
816

817
        last := (*sl)[sl.Len()-1]
2✔
818
        *sl = (*sl)[:sl.Len()-1]
2✔
819

2✔
820
        return Some(last)
2✔
821
}
822

823
// Set sets the value at the specified index in the slice and returns the modified slice.
824
// This method modifies the original slice in place.
825
//
826
// Parameters:
827
//
828
// - index (Int): The index at which to set the new value.
829
// - val (T): The new value to be set at the specified index.
830
//
831
// Returns:
832
//
833
// - Slice[T]: The modified slice with the new value set at the specified index.
834
//
835
// Example usage:
836
//
837
// slice := g.Slice[int]{1, 2, 3, 4, 5}
838
// slice.Set(2, 99)
839
// fmt.Println(slice)
840
//
841
// Output: [1 2 99 4 5].
842
func (sl Slice[T]) Set(index Int, val T) {
17✔
843
        i := sl.bound(index)
17✔
844
        if i.IsErr() {
17✔
NEW
845
                panic(i.Err())
×
846
        }
847

848
        sl[i.Ok()] = val
17✔
849
}
850

851
// Len returns the length of the slice.
852
func (sl Slice[T]) Len() Int { return Int(len(sl)) }
12,882✔
853

854
// Swap swaps the elements at the specified indices in the slice.
855
// This method modifies the original slice in place.
856
//
857
// Parameters:
858
//
859
// - i (Int): The index of the first element to be swapped.
860
//
861
// - j (Int): The index of the second element to be swapped.
862
//
863
// Returns:
864
//
865
// - Slice[T]: The modified slice with the elements at the specified indices swapped.
866
//
867
// Example usage:
868
//
869
// slice := g.Slice[int]{1, 2, 3, 4, 5}
870
// slice.Swap(1, 3)
871
// fmt.Println(slice)
872
//
873
// Output: [1 4 3 2 5].
874
func (sl Slice[T]) Swap(i, j Int) {
2✔
875
        ii := sl.bound(i)
2✔
876
        jj := sl.bound(j)
2✔
877

2✔
878
        if ii.IsErr() {
2✔
NEW
879
                panic(ii.Err())
×
880
        }
881

882
        if jj.IsErr() {
2✔
NEW
883
                panic(jj.Err())
×
884
        }
885

886
        sl.swap(ii.Ok(), jj.Ok())
2✔
887
}
888

889
func (sl Slice[T]) swap(i, j Int) { sl[i], sl[j] = sl[j], sl[i] }
20✔
890

891
// Grow increases the slice's capacity, if necessary, to guarantee space for
892
// another n elements. After Grow(n), at least n elements can be appended
893
// to the slice without another allocation. If n is negative or too large to
894
// allocate the memory, Grow panics.
895
func (sl Slice[T]) Grow(n Int) Slice[T] { return slices.Grow(sl, n.Std()) }
1✔
896

897
// Clip removes unused capacity from the slice.
898
func (sl Slice[T]) Clip() Slice[T] { return slices.Clip(sl) }
×
899

900
// Std returns a new slice with the same elements as the Slice[T].
901
func (sl Slice[T]) Std() []T { return sl }
1✔
902

903
// Print writes the elements of the Slice to the standard output (console)
904
// and returns the Slice unchanged.
NEW
905
func (sl Slice[T]) Print() Slice[T] { fmt.Print(sl); return sl }
×
906

907
// Println writes the elements of the Slice to the standard output (console) with a newline
908
// and returns the Slice unchanged.
NEW
909
func (sl Slice[T]) Println() Slice[T] { fmt.Println(sl); return sl }
×
910

911
// Unpack assigns values of the slice's elements to the variables passed as pointers.
912
// If the number of variables passed is greater than the length of the slice,
913
// the function ignores the extra variables.
914
//
915
// Parameters:
916
//
917
// - vars (...*T): Pointers to variables where the values of the slice's elements will be stored.
918
//
919
// Example:
920
//
921
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
922
//        var a, b, c int
923
//        slice.Unpack(&a, &b, &c)
924
//        fmt.Println(a, b, c) // Output: 1 2 3
925
func (sl Slice[T]) Unpack(vars ...*T) {
4✔
926
        if len(vars) > len(sl) {
7✔
927
                vars = vars[:len(sl)]
3✔
928
        }
3✔
929

930
        for i, v := range vars {
10✔
931
                *v = sl[i]
6✔
932
        }
6✔
933
}
934

935
// MaxBy returns the maximum value in the slice according to the provided comparison function fn.
936
// It applies fn pairwise to the elements of the slice until it finds the maximum value.
937
// It returns the maximum value found.
938
//
939
// Example:
940
//
941
//        s := Slice[int]{3, 1, 4, 2, 5}
942
//        maxInt := s.MaxBy(cmp.Cmp)
943
//        fmt.Println(maxInt) // Output: 5
944
func (sl Slice[T]) MaxBy(fn func(a, b T) cmp.Ordering) T { return cmp.MaxBy(fn, sl...) }
1✔
945

946
// MinBy returns the minimum value in the slice according to the provided comparison function fn.
947
// It applies fn pairwise to the elements of the slice until it finds the minimum value.
948
// It returns the minimum value found.
949
//
950
// Example:
951
//
952
//        s := Slice[int]{3, 1, 4, 2, 5}
953
//        minInt := s.MinBy(cmp.Cmp)
954
//        fmt.Println(minInt) // Output: 1
955
func (sl Slice[T]) MinBy(fn func(a, b T) cmp.Ordering) T { return cmp.MinBy(fn, sl...) }
1✔
956

957
func (sl Slice[T]) bound(i Int, subslice ...struct{}) Result[Int] {
530✔
958
        if sl.Empty() {
778✔
959
                return Err[Int](fmt.Errorf("runtime error: slice is empty"))
248✔
960
        }
248✔
961

962
        ii := i
282✔
963
        if ii < 0 {
311✔
964
                ii += sl.Len()
29✔
965
        }
29✔
966

967
        var negative Int
282✔
968
        if len(subslice) != 0 {
350✔
969
                negative = -1
68✔
970
        }
68✔
971

972
        if ii > sl.Len() || ii < negative {
285✔
973
                return Err[Int](Errorf("runtime error: slice bounds out of range [{}] with length {}", i, len(sl)))
3✔
974
        }
3✔
975

976
        return Ok(ii)
279✔
977
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc