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

enetx / g / 21222265366

21 Jan 2026 07:06PM UTC coverage: 89.815% (-0.4%) from 90.189%
21222265366

push

github

enetx
mutex, rwlock

40 of 40 new or added lines in 2 files covered. (100.0%)

29 existing lines in 4 files now uncovered.

6420 of 7148 relevant lines covered (89.82%)

313.12 hits per line

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

88.36
/slice.go
1
package g
2

3
import (
4
        "bytes"
5
        "errors"
6
        "fmt"
7
        "math/rand/v2"
8
        "slices"
9
        "strconv"
10
        "strings"
11

12
        "github.com/enetx/g/cmp"
13
        "github.com/enetx/g/f"
14
        "github.com/enetx/iter"
15
)
16

17
// NewSlice creates a new Slice of the given generic type T with the specified length and
18
// capacity.
19
// The size variadic parameter can have zero, one, or two integer values.
20
// If no values are provided, an empty Slice with a length and capacity of 0 is returned.
21
// If one value is provided, it sets both the length and capacity of the Slice.
22
// If two values are provided, the first value sets the length and the second value sets the
23
// capacity.
24
//
25
// Parameters:
26
//
27
// - size ...Int: A variadic parameter specifying the length and/or capacity of the Slice
28
//
29
// Returns:
30
//
31
// - Slice[T]: A new Slice of the specified generic type T with the given length and capacity
32
//
33
// Example usage:
34
//
35
//        s1 := g.NewSlice[int]()        // Creates an empty Slice of type int
36
//        s2 := g.NewSlice[int](5)       // Creates an Slice with length and capacity of 5
37
//        s3 := g.NewSlice[int](3, 10)   // Creates an Slice with length of 3 and capacity of 10
38
func NewSlice[T any](size ...Int) Slice[T] {
118✔
39
        var (
118✔
40
                length   Int
118✔
41
                capacity Int
118✔
42
        )
118✔
43

118✔
44
        switch {
118✔
45
        case len(size) > 1:
1✔
46
                length, capacity = size[0], size[1]
1✔
47
        case len(size) == 1:
27✔
48
                length, capacity = size[0], size[0]
27✔
49
        }
50

51
        return make(Slice[T], length, capacity)
118✔
52
}
53

54
// TransformSlice 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 TransformSlice[T, U any](sl Slice[T], fn func(T) U) Slice[U] {
43✔
67
        if len(sl) == 0 {
56✔
68
                return NewSlice[U]()
13✔
69
        }
13✔
70

71
        result := make(Slice[U], len(sl))
30✔
72
        for i, v := range sl {
91✔
73
                result[i] = fn(v)
61✔
74
        }
61✔
75

76
        return result
30✔
77
}
78

79
// SliceOf creates a new generic slice containing the provided elements.
80
func SliceOf[T any](slice ...T) Slice[T] { return slice }
317✔
81

82
// ToHeap converts the slice to a min/max heap with the specified comparison function.
83
//
84
// The comparison function should return:
85
//   - cmp.Less if a < b (for min heap)
86
//   - cmp.Greater if a > b (for max heap)
87
//   - cmp.Equal if a == b
88
//
89
// Example usage:
90
//
91
//        slice := g.SliceOf(5, 2, 8, 1, 9)
92
//
93
//        minHeap := slice.ToHeap(cmp.Cmp[int])        // Min heap: Pop() returns smallest
94
//        maxHeap := slice.ToHeap(func(a, b int) cmp.Ordering {
95
//                return cmp.Cmp(b, a)
96
//        })        // Max heap: Pop() returns largest
97
//
98
// Time complexity: O(n)
99
// Space complexity: O(n) - creates a copy of the slice
100
func (sl Slice[T]) ToHeap(compareFn func(T, T) cmp.Ordering) *Heap[T] {
1✔
101
        if compareFn == nil {
1✔
102
                panic("compareFn cannot be nil")
×
103
        }
104

105
        h := &Heap[T]{
1✔
106
                data: make(Slice[T], len(sl)),
1✔
107
                cmp:  compareFn,
1✔
108
        }
1✔
109

1✔
110
        copy(h.data, sl)
1✔
111
        h.heapify()
1✔
112

1✔
113
        return h
1✔
114
}
115

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

119
// Iter returns an iterator (SeqSlice[T]) for the Slice, allowing for sequential iteration
120
// over its elements. It is commonly used in combination with higher-order functions,
121
// such as 'ForEach', to perform operations on each element of the Slice.
122
//
123
// Returns:
124
//
125
// A SeqSlice[T], which can be used for sequential iteration over the elements of the Slice.
126
//
127
// Example usage:
128
//
129
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
130
//        iterator := slice.Iter()
131
//        iterator.ForEach(func(element int) {
132
//                // Perform some operation on each element
133
//                fmt.Println(element)
134
//        })
135
//
136
// The 'Iter' method provides a convenient way to traverse the elements of a Slice
137
// in a functional style, enabling operations like mapping or filtering.
138
func (sl Slice[T]) Iter() SeqSlice[T] { return SeqSlice[T](iter.FromSlice(sl)) }
252✔
139

140
// IterReverse returns an iterator (SeqSlice[T]) for the Slice that allows for sequential iteration
141
// over its elements in reverse order. This method is useful when you need to traverse the elements
142
// from the end to the beginning.
143
//
144
// Returns:
145
//
146
// A SeqSlice[T], which can be used for sequential iteration over the elements of the Slice in reverse order.
147
//
148
// Example usage:
149
//
150
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
151
//        iterator := slice.IterReverse()
152
//        iterator.ForEach(func(element int) {
153
//                // Perform some operation on each element in reverse order
154
//                fmt.Println(element)
155
//        })
156
//
157
// The 'IterReverse' method enhances the functionality of the Slice by providing an alternative
158
// way to iterate through its elements, enhancing flexibility in how data within a Slice is accessed and manipulated.
159
func (sl Slice[T]) IterReverse() SeqSlice[T] { return SeqSlice[T](iter.FromSliceReverse(sl)) }
3✔
160

161
// AsAny converts each element of the slice to the 'any' type.
162
// It returns a new slice containing the elements as 'any' g.Slice[any].
163
//
164
// Note: AsAny is useful when you want to work with a slice of a specific type as a slice of 'any'.
165
// It can be particularly handy in conjunction with Flatten to work with nested slices of different types.
166
func (sl Slice[T]) AsAny() Slice[any] {
3✔
167
        if sl.Empty() {
3✔
168
                return NewSlice[any]()
×
169
        }
×
170

171
        result := make(Slice[any], len(sl))
3✔
172
        for i, v := range sl {
12✔
173
                result[i] = any(v)
9✔
174
        }
9✔
175

176
        return result
3✔
177
}
178

179
// Fill fills the slice with the specified value.
180
// This function is useful when you want to create an Slice with all elements having the same
181
// value.
182
// This method modifies the original slice in place.
183
//
184
// Parameters:
185
//
186
// - val T: The value to fill the Slice with.
187
//
188
// Returns:
189
//
190
// - Slice[T]: A reference to the original Slice filled with the specified value.
191
//
192
// Example usage:
193
//
194
//        slice := g.Slice[int]{0, 0, 0}
195
//        slice.Fill(5)
196
//
197
// The modified slice will now contain: 5, 5, 5.
198
func (sl Slice[T]) Fill(val T) {
3✔
199
        if len(sl) == 0 {
4✔
200
                return
1✔
201
        }
1✔
202

203
        if len(sl) > 32 {
3✔
204
                sl[0] = val
1✔
205
                for i := 1; i < len(sl); i <<= 1 {
8✔
206
                        copy(sl[i:], sl[:i])
7✔
207
                }
7✔
208
        } else {
1✔
209
                for i := range sl {
6✔
210
                        sl[i] = val
5✔
211
                }
5✔
212
        }
213
}
214

215
// Index returns the index of the first occurrence of the specified value in the slice, or -1 if
216
// not found.
217
func (sl Slice[T]) Index(val T) Int {
107✔
218
        var zero T
107✔
219
        if f.IsComparable(zero) {
214✔
220
                return sl.IndexBy(func(v T) bool { return f.Eq[any](v)(val) })
453✔
221
        }
222

223
        return sl.IndexBy(f.Eqd(val))
×
224
}
225

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

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

255
        if sequence.Lte(0) {
5✔
256
                return Slice[T]{}
×
257
        }
×
258

259
        n := len(sl)
5✔
260

5✔
261
        if Float(sequence).Lt(Float(n) * 0.25) {
5✔
UNCOV
262
                result := make(Slice[T], sequence)
×
UNCOV
263
                swapped := make(map[int]int, sequence)
×
UNCOV
264

×
UNCOV
265
                for i := range int(sequence) {
×
UNCOV
266
                        j := i + rand.N(n-i)
×
UNCOV
267

×
UNCOV
268
                        vi, foundI := swapped[i]
×
UNCOV
269
                        if !foundI {
×
UNCOV
270
                                vi = i
×
UNCOV
271
                        }
×
272

UNCOV
273
                        vj, foundJ := swapped[j]
×
UNCOV
274
                        if !foundJ {
×
UNCOV
275
                                vj = j
×
UNCOV
276
                        }
×
277

UNCOV
278
                        swapped[i] = vj
×
UNCOV
279
                        if i != j {
×
UNCOV
280
                                swapped[j] = vi
×
UNCOV
281
                        }
×
282

UNCOV
283
                        result[i] = sl[vj]
×
284
                }
285

UNCOV
286
                return result
×
287
        }
288

289
        result := sl.Clone()
5✔
290
        result.Shuffle()
5✔
291

5✔
292
        return result[:sequence]
5✔
293
}
294

295
// RandomRange returns a new slice containing a random sample of elements from a subrange of the original slice.
296
// The sampling is done without replacement, meaning that each element can only appear once in the result.
297
func (sl Slice[T]) RandomRange(from, to Int) Slice[T] {
6✔
298
        if from < 0 {
7✔
299
                from = 0
1✔
300
        }
1✔
301

302
        if to < 0 || to > sl.Len() {
9✔
303
                to = sl.Len()
3✔
304
        }
3✔
305

306
        if from > to {
7✔
307
                from = to
1✔
308
        }
1✔
309

310
        return sl.RandomSample(from.RandomRange(to))
6✔
311
}
312

313
// Insert inserts values at the specified index in the slice and modifies the original
314
// slice.
315
//
316
// Parameters:
317
//
318
// - i Int: The index at which to insert the new values.
319
//
320
// - values ...T: A variadic list of values to insert at the specified index.
321
//
322
// Example usage:
323
//
324
//        slice := g.Slice[string]{"a", "b", "c", "d"}
325
//        slice.Insert(2, "e", "f")
326
//
327
// The resulting slice will be: ["a", "b", "e", "f", "c", "d"].
328
func (sl *Slice[T]) Insert(i Int, values ...T) {
51✔
329
        if sl.Empty() {
52✔
330
                if i != 0 {
1✔
331
                        panic(Errorf("runtime error: slice bounds out of range [{}] with length 0", i))
×
332
                }
333

334
                sl.Push(values...)
1✔
335
                return
1✔
336
        }
337

338
        sl.Replace(i, i, values...)
50✔
339
}
340

341
// Replace replaces the elements of sl[i:j] with the given values,
342
// and modifies the original slice in place. Replace panics if sl[i:j]
343
// is not a valid slice of sl.
344
//
345
// Parameters:
346
//
347
// - i int: The starting index of the slice to be replaced.
348
//
349
// - j int: The ending index of the slice to be replaced.
350
//
351
// - values ...T: A variadic list of values to replace the existing slice.
352
//
353
// Example usage:
354
//
355
//        slice := g.Slice[string]{"a", "b", "c", "d"}
356
//        slice.Replace(1, 3, "e", "f")
357
//
358
// After the Replace operation, the resulting slice will be: ["a", "e", "f", "d"].
359
func (sl *Slice[T]) Replace(i, j Int, values ...T) {
61✔
360
        ii := sl.bound(i)
61✔
361
        jj := sl.bound(j)
61✔
362

61✔
363
        if ii.IsErr() {
61✔
364
                panic(ii.err)
×
365
        }
366
        if jj.IsErr() {
61✔
367
                panic(jj.err)
×
368
        }
369

370
        i, j = ii.v, jj.v
61✔
371

61✔
372
        if i > j {
61✔
373
                *sl = (*sl)[:0]
×
374
                return
×
375
        }
×
376

377
        oldLen := sl.Len()
61✔
378
        removedCount := j - i
61✔
379
        addedCount := Int(len(values))
61✔
380
        newLen := oldLen - removedCount + addedCount
61✔
381

61✔
382
        if i == j {
111✔
383
                if addedCount == 0 {
50✔
384
                        return
×
385
                }
×
386

387
                if newLen > sl.Cap() {
100✔
388
                        newSlice := make(Slice[T], newLen)
50✔
389
                        copy(newSlice[:i], (*sl)[:i])
50✔
390
                        copy(newSlice[i:i+addedCount], values)
50✔
391
                        copy(newSlice[i+addedCount:], (*sl)[i:])
50✔
392
                        *sl = newSlice
50✔
393
                } else {
50✔
394
                        *sl = (*sl)[:newLen]
×
395
                        copy((*sl)[i+addedCount:], (*sl)[i:oldLen])
×
396
                        copy((*sl)[i:], values)
×
397
                }
×
398
                return
50✔
399
        }
400

401
        if newLen > sl.Cap() {
12✔
402
                newSlice := make(Slice[T], newLen)
1✔
403
                copy(newSlice[:i], (*sl)[:i])
1✔
404
                copy(newSlice[i:i+addedCount], values)
1✔
405
                copy(newSlice[i+addedCount:], (*sl)[j:])
1✔
406
                *sl = newSlice
1✔
407
        } else {
11✔
408
                if newLen != oldLen {
16✔
409
                        *sl = (*sl)[:newLen]
6✔
410
                }
6✔
411

412
                if addedCount != removedCount {
16✔
413
                        copy((*sl)[i+addedCount:], (*sl)[j:oldLen])
6✔
414
                }
6✔
415

416
                copy((*sl)[i:], values)
10✔
417
        }
418
}
419

420
// Get returns the element at the given index, handling negative indices as counting from the end
421
// of the slice.
422
func (sl Slice[T]) Get(index Int) Option[T] {
590✔
423
        i := sl.bound(index)
590✔
424
        if i.IsErr() {
977✔
425
                return None[T]()
387✔
426
        }
387✔
427

428
        return Some(sl[i.v])
203✔
429
}
430

431
// Shuffle shuffles the elements in the slice randomly.
432
// This method modifies the original slice in place.
433
//
434
// Example usage:
435
//
436
// slice := g.Slice[int]{1, 2, 3, 4, 5}
437
// slice.Shuffle()
438
// fmt.Println(slice)
439
//
440
// Output: A randomly shuffled version of the original slice, e.g., [4 1 5 2 3].
441
func (sl Slice[T]) Shuffle() {
6✔
442
        for i := sl.Len() - 1; i > 0; i-- {
40✔
443
                j := rand.N(i + 1)
34✔
444
                sl[i], sl[j] = sl[j], sl[i]
34✔
445
        }
34✔
446
}
447

448
// Reverse reverses the order of the elements in the slice.
449
// This method modifies the original slice in place.
450
//
451
// Returns:
452
//
453
// - Slice[T]: The modified slice with the elements reversed.
454
//
455
// Example usage:
456
//
457
// slice := g.Slice[int]{1, 2, 3, 4, 5}
458
// slice.Reverse()
459
// fmt.Println(slice)
460
//
461
// Output: [5 4 3 2 1].
462
func (sl Slice[T]) Reverse() { slices.Reverse(sl) }
1✔
463

464
// SortBy sorts the elements in the slice using the provided comparison function.
465
// It modifies the original slice in place. It requires the elements to be of a type
466
// that is comparable.
467
//
468
// The function takes a custom comparison function as an argument and sorts the elements
469
// of the slice using the provided logic. The comparison function should return true if
470
// the element at index i should come before the element at index j, and false otherwise.
471
//
472
// Parameters:
473
//
474
// - f func(a, b T) cmp.Ordered: A comparison function that takes two indices i and j and returns a bool.
475
//
476
// Example usage:
477
//
478
// sl := NewSlice[int](1, 5, 3, 2, 4)
479
// sl.SortBy(func(a, b int) cmp.Ordering { return cmp.Cmp(a, b) }) // sorts in ascending order.
480
func (sl Slice[T]) SortBy(fn func(a, b T) cmp.Ordering) {
26✔
481
        slices.SortFunc(sl, func(a, b T) int { return int(fn(a, b)) })
132✔
482
}
483

484
// IsSortedBy checks if the slice is sorted according to the provided comparison function.
485
//
486
// The function takes a custom comparison function as an argument and checks if the elements
487
// are sorted according to the provided logic.
488
//
489
// Parameters:
490
//
491
// - fn func(a, b T) cmp.Ordering: A comparison function that defines the sort order.
492
//
493
// Returns:
494
//
495
// - bool: true if the slice is sorted according to the comparison function, false otherwise.
496
//
497
// Example usage:
498
//
499
//        sl := g.SliceOf(1, 2, 3, 4, 5)
500
//        sorted := sl.IsSortedBy(func(a, b int) cmp.Ordering { return cmp.Cmp(a, b) }) // returns true
501
func (sl Slice[T]) IsSortedBy(fn func(a, b T) cmp.Ordering) bool {
9✔
502
        if len(sl) <= 1 {
11✔
503
                return true
2✔
504
        }
2✔
505

506
        for i := 1; i < len(sl); i++ {
24✔
507
                if fn(sl[i-1], sl[i]).IsGt() {
20✔
508
                        return false
3✔
509
                }
3✔
510
        }
511

512
        return true
4✔
513
}
514

515
// ToStringSlice converts the Slice into a slice of strings.
516
func (sl Slice[T]) ToStringSlice() []string {
57✔
517
        if len(sl) == 0 {
58✔
518
                return nil
1✔
519
        }
1✔
520

521
        result := make([]string, len(sl))
56✔
522

56✔
523
        for i, v := range sl {
174✔
524
                switch val := any(v).(type) {
118✔
525
                case String:
96✔
526
                        result[i] = val.Std()
96✔
527
                case Int:
1✔
528
                        result[i] = strconv.FormatInt(int64(val), 10)
1✔
529
                case Float:
1✔
530
                        result[i] = strconv.FormatFloat(float64(val), 'g', -1, 64)
1✔
531
                case Bytes:
1✔
532
                        result[i] = string(val)
1✔
533
                case string:
1✔
534
                        result[i] = val
1✔
535
                case int:
4✔
536
                        result[i] = strconv.Itoa(val)
4✔
537
                case int8:
1✔
538
                        result[i] = strconv.FormatInt(int64(val), 10)
1✔
539
                case int16:
1✔
540
                        result[i] = strconv.FormatInt(int64(val), 10)
1✔
541
                case int32:
1✔
542
                        result[i] = strconv.FormatInt(int64(val), 10)
1✔
543
                case int64:
1✔
544
                        result[i] = strconv.FormatInt(val, 10)
1✔
545
                case uint:
1✔
546
                        result[i] = strconv.FormatUint(uint64(val), 10)
1✔
547
                case uint8:
1✔
548
                        result[i] = strconv.FormatUint(uint64(val), 10)
1✔
549
                case uint16:
1✔
550
                        result[i] = strconv.FormatUint(uint64(val), 10)
1✔
551
                case uint32:
1✔
552
                        result[i] = strconv.FormatUint(uint64(val), 10)
1✔
553
                case uint64:
1✔
554
                        result[i] = strconv.FormatUint(val, 10)
1✔
555
                case float32:
1✔
556
                        result[i] = strconv.FormatFloat(float64(val), 'g', -1, 32)
1✔
557
                case float64:
1✔
558
                        result[i] = strconv.FormatFloat(val, 'g', -1, 64)
1✔
559
                case bool:
2✔
560
                        result[i] = strconv.FormatBool(val)
2✔
561
                default:
1✔
562
                        if stringer, ok := any(v).(fmt.Stringer); ok {
1✔
563
                                result[i] = stringer.String()
×
564
                        } else {
1✔
565
                                result[i] = fmt.Sprint(v)
1✔
566
                        }
1✔
567
                }
568
        }
569

570
        return result
56✔
571
}
572

573
// Join joins the elements in the slice into a single String, separated by the provided separator (if any).
574
func (sl Slice[T]) Join(sep ...T) String {
10✔
575
        if sl.Empty() {
11✔
576
                return ""
1✔
577
        }
1✔
578

579
        if s, ok := any(sl).(Slice[Bytes]); ok {
10✔
580
                var separator Bytes
1✔
581
                if len(sep) != 0 {
2✔
582
                        separator, _ = any(sep[0]).(Bytes)
1✔
583
                }
1✔
584

585
                return String(bytes.Join(TransformSlice(s, func(b Bytes) []byte { return b }), separator))
6✔
586
        }
587

588
        if s, ok := any(sl).(Slice[String]); ok {
16✔
589
                var separator string
8✔
590
                if len(sep) != 0 {
16✔
591
                        if sepStr, ok := any(sep[0]).(String); ok {
16✔
592
                                separator = sepStr.Std()
8✔
593
                        } else {
8✔
594
                                separator = fmt.Sprint(sep[0])
×
595
                        }
×
596
                }
597

598
                strs := make([]string, len(s))
8✔
599
                for i, str := range s {
39✔
600
                        strs[i] = str.Std()
31✔
601
                }
31✔
602

603
                return String(strings.Join(strs, separator))
8✔
604
        }
605

606
        var separator string
×
607
        if len(sep) != 0 {
×
608
                separator = fmt.Sprint(sep[0])
×
609
        }
×
610

611
        return String(strings.Join(sl.ToStringSlice(), separator))
×
612
}
613

614
// SubSlice returns a new slice containing elements from the current slice between the specified start
615
// and end indices, with an optional step parameter to define the increment between elements.
616
// The function checks if the start and end indices are within the bounds of the original slice.
617
// If the end index is negative, it represents the position from the end of the slice.
618
// If the start index is negative, it represents the position from the end of the slice counted
619
// from the start index.
620
//
621
// Parameters:
622
//
623
// - start (Int): The start index of the range.
624
//
625
// - end (Int): The end index of the range.
626
//
627
// - step (Int, optional): The increment between elements. Defaults to 1 if not provided.
628
// If negative, the slice is traversed in reverse order.
629
//
630
// Returns:
631
//
632
// - Slice[T]: A new slice containing elements from the current slice between the start and end
633
// indices, with the specified step.
634
//
635
// Example usage:
636
//
637
//        slice := g.Slice[int]{1, 2, 3, 4, 5, 6, 7, 8, 9}
638
//        subSlice := slice.SubSlice(1, 7, 2) // Extracts elements 2, 4, 6
639
//        fmt.Println(subSlice)
640
//
641
// Output: [2 4 6].
642
func (sl Slice[T]) SubSlice(start, end Int, step ...Int) Slice[T] {
35✔
643
        if sl.Empty() {
36✔
644
                return sl
1✔
645
        }
1✔
646

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

34✔
649
        ii := sl.bound(start, Unit{})
34✔
650
        jj := sl.bound(end, Unit{})
34✔
651

34✔
652
        if ii.IsErr() {
36✔
653
                panic(ii.err)
2✔
654
        }
655

656
        if jj.IsErr() {
33✔
657
                panic(jj.err)
1✔
658
        }
659

660
        start, end = ii.v, jj.v
31✔
661

31✔
662
        if _step == 1 {
44✔
663
                if start >= end {
15✔
664
                        return NewSlice[T]()
2✔
665
                }
2✔
666

667
                return slices.Clone(sl[start:end])
11✔
668
        }
669

670
        if (start >= end && _step > 0) || (start <= end && _step < 0) || _step == 0 {
19✔
671
                return NewSlice[T]()
1✔
672
        }
1✔
673

674
        var resultSize Int
17✔
675
        if _step > 0 {
23✔
676
                resultSize = (end - start + _step - 1) / _step
6✔
677
        } else {
17✔
678
                resultSize = (start - end + (-_step) - 1) / (-_step)
11✔
679
        }
11✔
680

681
        slice := make(Slice[T], 0, resultSize)
17✔
682

17✔
683
        var loopCondition func(Int) bool
17✔
684
        if _step > 0 {
23✔
685
                loopCondition = func(i Int) bool { return i < end }
35✔
686
        } else {
11✔
687
                loopCondition = func(i Int) bool { return i > end }
69✔
688
        }
689

690
        for i := start; loopCondition(i); i += _step {
87✔
691
                slice = append(slice, sl[i])
70✔
692
        }
70✔
693

694
        return slice
17✔
695
}
696

697
// Random returns a random element from the slice.
698
// If the slice is empty, the zero value of type T is returned.
699
//
700
// Returns:
701
//
702
// - T: A random element from the slice.
703
//
704
// Example usage:
705
//
706
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
707
//        randomElement := slice.Random()
708
//        fmt.Println(randomElement)
709
//
710
// Output: <any random element from the slice>.
711
func (sl Slice[T]) Random() T {
12,476✔
712
        if sl.Empty() {
12,477✔
713
                var zero T
1✔
714
                return zero
1✔
715
        }
1✔
716

717
        return sl[rand.N(len(sl))]
12,475✔
718
}
719

720
// Clone returns a copy of the slice.
721
func (sl Slice[T]) Clone() Slice[T] {
175✔
722
        if sl.Empty() {
195✔
723
                return NewSlice[T]()
20✔
724
        }
20✔
725

726
        return slices.Clone(sl)
155✔
727
}
728

729
// LastIndex returns the last index of the slice.
730
func (sl Slice[T]) LastIndex() Int {
2✔
731
        if sl.NotEmpty() {
3✔
732
                return sl.Len() - 1
1✔
733
        }
1✔
734

735
        return 0
1✔
736
}
737

738
// Eq returns true if the slice is equal to the provided other slice.
739
func (sl Slice[T]) Eq(other Slice[T]) bool {
116✔
740
        var zero T
116✔
741
        if f.IsComparable(zero) {
225✔
742
                return sl.EqBy(other, func(x, y T) bool { return f.Eq[any](x)(y) })
490✔
743
        }
744

745
        return sl.EqBy(other, func(x, y T) bool { return f.Eqd(x)(y) })
23✔
746
}
747

748
// EqBy reports whether two slices are equal using an equality
749
// function on each pair of elements. If the lengths are different,
750
// EqBy returns false. Otherwise, the elements are compared in
751
// increasing index order, and the comparison stops at the first index
752
// for which eq returns false.
753
func (sl Slice[T]) EqBy(other Slice[T], fn func(x, y T) bool) bool {
121✔
754
        return slices.EqualFunc(sl, other, fn)
121✔
755
}
121✔
756

757
// String returns a string representation of the slice.
758
func (sl Slice[T]) String() string {
49✔
759
        if len(sl) == 0 {
49✔
760
                return "Slice[]"
×
761
        }
×
762

763
        var b Builder
49✔
764
        b.WriteString("Slice[")
49✔
765

49✔
766
        for i, v := range sl {
181✔
767
                if i > 0 {
215✔
768
                        b.WriteString(", ")
83✔
769
                }
83✔
770

771
                b.WriteString(Format("{}", v))
132✔
772
        }
773

774
        b.WriteString("]")
49✔
775

49✔
776
        return b.String().Std()
49✔
777
}
778

779
// Append appends the provided elements to the slice and returns the modified slice.
780
func (sl Slice[T]) Append(elems ...T) Slice[T] { return append(sl, elems...) }
24✔
781

782
// AppendUnique appends unique elements from the provided arguments to the current slice.
783
//
784
// The function iterates over the provided elements and checks if they are already present
785
// in the slice. If an element is not already present, it is appended to the slice. The
786
// resulting slice is returned, containing the unique elements from both the original
787
// slice and the provided elements.
788
//
789
// Parameters:
790
//
791
// - elems (...T): A variadic list of elements to be appended to the slice.
792
//
793
// Returns:
794
//
795
// - Slice[T]: A new slice containing the unique elements from both the original slice
796
// and the provided elements.
797
//
798
// Example usage:
799
//
800
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
801
//        slice = slice.AppendUnique(3, 4, 5, 6, 7)
802
//        fmt.Println(slice)
803
//
804
// Output: [1 2 3 4 5 6 7].
805
func (sl Slice[T]) AppendUnique(elems ...T) Slice[T] {
2✔
806
        for _, elem := range elems {
7✔
807
                if !sl.Contains(elem) {
8✔
808
                        sl = append(sl, elem)
3✔
809
                }
3✔
810
        }
811

812
        return sl
2✔
813
}
814

815
// Push appends the provided elements to the slice and modifies the original slice.
816
func (sl *Slice[T]) Push(elems ...T) { *sl = append(*sl, elems...) }
66✔
817

818
// PushUnique appends unique elements from the provided arguments to the current slice.
819
//
820
// The function iterates over the provided elements and checks if they are already present
821
// in the slice. If an element is not already present, it is appended to the slice.
822
//
823
// Parameters:
824
//
825
// - elems (...T): A variadic list of elements to be appended to the slice.
826
//
827
// Example usage:
828
//
829
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
830
//        slice.PushUnique(3, 4, 5, 6, 7)
831
//        fmt.Println(slice)
832
//
833
// Output: [1 2 3 4 5 6 7].
834
func (sl *Slice[T]) PushUnique(elems ...T) {
3✔
835
        for _, elem := range elems {
16✔
836
                if !sl.Contains(elem) {
18✔
837
                        sl.Push(elem)
5✔
838
                }
5✔
839
        }
840
}
841

842
// Cap returns the capacity of the Slice.
843
func (sl Slice[T]) Cap() Int { return Int(cap(sl)) }
63✔
844

845
// Contains returns true if the slice contains the provided value.
846
func (sl Slice[T]) Contains(val T) bool { return sl.Index(val) >= 0 }
87✔
847

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

851
// ContainsAny checks if the Slice contains any element from another Slice.
852
func (sl Slice[T]) ContainsAny(values ...T) bool {
8✔
853
        if sl.Empty() || len(values) == 0 {
10✔
854
                return false
2✔
855
        }
2✔
856

857
        return slices.ContainsFunc(values, sl.Contains)
6✔
858
}
859

860
// ContainsAll checks if the Slice contains all elements from another Slice.
861
func (sl Slice[T]) ContainsAll(values ...T) bool {
8✔
862
        if sl.Empty() || len(values) == 0 {
10✔
863
                return len(values) == 0
2✔
864
        }
2✔
865

866
        for _, v := range values {
32✔
867
                if !sl.Contains(v) {
28✔
868
                        return false
2✔
869
                }
2✔
870
        }
871

872
        return true
4✔
873
}
874

875
// Delete removes an element or a range of elements from the Slice in-place.
876
// It modifies the original Slice by creating two slices: one from the
877
// beginning of the Slice up to the specified `start` index (exclusive),
878
// and another from the `end` index (inclusive) to the end of the Slice.
879
// These two slices are then concatenated to form the modified Slice.
880
//
881
// Parameters:
882
//
883
//   - start (Int): The starting index of the element or range to be removed.
884
//   - end (Int, optional): The end index of the range to be removed.
885
//     If omitted, only the element at the `start` index is removed.
886
//
887
// Note:
888
//
889
// The function supports negative indices. Negative values are counted from
890
// the end of the Slice: for example, -1 refers to the last element, -2 to
891
// the second-to-last, and so on.
892
func (sl *Slice[T]) Delete(start Int, end ...Int) {
5✔
893
        sl.Replace(start, Slice[Int](end).Get(0).UnwrapOr(start+1))
5✔
894
}
5✔
895

896
// Empty returns true if the slice is empty.
897
func (sl Slice[T]) Empty() bool { return len(sl) == 0 }
13,644✔
898

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

902
// Ne returns true if the slice is not equal to the provided other slice.
903
func (sl Slice[T]) Ne(other Slice[T]) bool { return !sl.Eq(other) }
14✔
904

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

912
// NotEmpty checks if the Slice is not empty.
913
func (sl Slice[T]) NotEmpty() bool { return !sl.Empty() }
32✔
914

915
// Pop removes and returns the last element of the slice.
916
// It mutates the original slice by removing the last element.
917
// It returns None if the slice is empty.
918
func (sl *Slice[T]) Pop() Option[T] {
22✔
919
        if sl.Len() == 0 {
22✔
920
                return None[T]()
×
921
        }
×
922

923
        last := (*sl)[sl.Len()-1]
22✔
924
        *sl = (*sl)[:sl.Len()-1]
22✔
925

22✔
926
        return Some(last)
22✔
927
}
928

929
// Set sets the value at the specified index in the slice and returns the modified slice.
930
// This method modifies the original slice in place.
931
//
932
// Parameters:
933
//
934
// - index (Int): The index at which to set the new value.
935
// - val (T): The new value to be set at the specified index.
936
//
937
// Returns:
938
//
939
// - Slice[T]: The modified slice with the new value set at the specified index.
940
//
941
// Example usage:
942
//
943
// slice := g.Slice[int]{1, 2, 3, 4, 5}
944
// slice.Set(2, 99)
945
// fmt.Println(slice)
946
//
947
// Output: [1 2 99 4 5].
948
func (sl Slice[T]) Set(index Int, val T) {
17✔
949
        i := sl.bound(index)
17✔
950
        if i.IsErr() {
17✔
951
                panic(i.err)
×
952
        }
953

954
        sl[i.v] = val
17✔
955
}
956

957
// Len returns the length of the slice.
958
func (sl Slice[T]) Len() Int { return Int(len(sl)) }
1,330✔
959

960
// Swap swaps the elements at the specified indices in the slice.
961
// This method modifies the original slice in place.
962
//
963
// Parameters:
964
//
965
// - i (Int): The index of the first element to be swapped.
966
//
967
// - j (Int): The index of the second element to be swapped.
968
//
969
// Returns:
970
//
971
// - Slice[T]: The modified slice with the elements at the specified indices swapped.
972
//
973
// Example usage:
974
//
975
// slice := g.Slice[int]{1, 2, 3, 4, 5}
976
// slice.Swap(1, 3)
977
// fmt.Println(slice)
978
//
979
// Output: [1 4 3 2 5].
980
func (sl Slice[T]) Swap(i, j Int) {
5✔
981
        ii := sl.bound(i)
5✔
982
        jj := sl.bound(j)
5✔
983

5✔
984
        if ii.IsErr() {
7✔
985
                panic(ii.err)
2✔
986
        }
987

988
        if jj.IsErr() {
4✔
989
                panic(jj.err)
1✔
990
        }
991

992
        sl[ii.v], sl[jj.v] = sl[jj.v], sl[ii.v]
2✔
993
}
994

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

1001
// Clip removes unused capacity from the slice.
1002
func (sl Slice[T]) Clip() Slice[T] { return slices.Clip(sl) }
1✔
1003

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

1007
// Print writes the elements of the Slice to the standard output (console)
1008
// and returns the Slice unchanged.
1009
func (sl Slice[T]) Print() Slice[T] { fmt.Print(sl); return sl }
1✔
1010

1011
// Println writes the elements of the Slice to the standard output (console) with a newline
1012
// and returns the Slice unchanged.
1013
func (sl Slice[T]) Println() Slice[T] { fmt.Println(sl); return sl }
1✔
1014

1015
// Unpack assigns values of the slice's elements to the variables passed as pointers.
1016
// If the number of variables passed is greater than the length of the slice,
1017
// the function ignores the extra variables.
1018
//
1019
// Parameters:
1020
//
1021
// - vars (...*T): Pointers to variables where the values of the slice's elements will be stored.
1022
//
1023
// Example:
1024
//
1025
//        slice := g.Slice[int]{1, 2, 3, 4, 5}
1026
//        var a, b, c int
1027
//        slice.Unpack(&a, &b, &c)
1028
//        fmt.Println(a, b, c) // Output: 1 2 3
1029
func (sl Slice[T]) Unpack(vars ...*T) {
4✔
1030
        n := min(len(sl), len(vars))
4✔
1031

4✔
1032
        for i := range n {
10✔
1033
                if vars[i] != nil {
12✔
1034
                        *vars[i] = sl[i]
6✔
1035
                }
6✔
1036
        }
1037
}
1038

1039
// MaxBy returns the maximum value in the slice according to the provided comparison function fn.
1040
// It applies fn pairwise to the elements of the slice until it finds the maximum value.
1041
// It returns the maximum value found.
1042
//
1043
// Example:
1044
//
1045
//        s := Slice[int]{3, 1, 4, 2, 5}
1046
//        maxInt := s.MaxBy(cmp.Cmp)
1047
//        fmt.Println(maxInt) // Output: 5
1048
func (sl Slice[T]) MaxBy(fn func(a, b T) cmp.Ordering) T { return cmp.MaxBy(fn, sl...) }
1✔
1049

1050
// MinBy returns the minimum value in the slice according to the provided comparison function fn.
1051
// It applies fn pairwise to the elements of the slice until it finds the minimum value.
1052
// It returns the minimum value found.
1053
//
1054
// Example:
1055
//
1056
//        s := Slice[int]{3, 1, 4, 2, 5}
1057
//        minInt := s.MinBy(cmp.Cmp)
1058
//        fmt.Println(minInt) // Output: 1
1059
func (sl Slice[T]) MinBy(fn func(a, b T) cmp.Ordering) T { return cmp.MinBy(fn, sl...) }
1✔
1060

1061
func (sl Slice[T]) bound(i Int, subslice ...Unit) Result[Int] {
807✔
1062
        if sl.Empty() {
1,194✔
1063
                return Err[Int](errors.New("runtime error: slice is empty"))
387✔
1064
        }
387✔
1065

1066
        ii := i
420✔
1067
        if ii < 0 {
450✔
1068
                ii += sl.Len()
30✔
1069
        }
30✔
1070

1071
        var negative Int
420✔
1072
        if len(subslice) != 0 {
488✔
1073
                negative = -1
68✔
1074
        }
68✔
1075

1076
        if ii > sl.Len() || ii < negative {
427✔
1077
                return Err[Int](Errorf("runtime error: slice bounds out of range [{}] with length {}", i, len(sl)))
7✔
1078
        }
7✔
1079

1080
        return Ok(ii)
413✔
1081
}
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

© 2026 Coveralls, Inc