Documentation
¶
Overview ¶
Package collection provides fluent, explicit pipelines over slices.
New borrows slices by default, while pure transformations return independent results and view operations document their shared storage. Use Clone to make backing-array ownership independent explicitly; element cloning is shallow.
Index ¶
- func Avg[S ~[]T, T Number](s S) float64
- func CountByValue[S ~[]T, T comparable](c S) map[T]int
- func Dump(vs ...any)
- func Max[S ~[]T, T Number](s S) (T, bool)
- func Median[S ~[]T, T Number](s S) (float64, bool)
- func Min[S ~[]T, T Number](s S) (T, bool)
- func Mode[S ~[]T, T Number](items S) []T
- func Sum[S ~[]T, T Number](s S) T
- type Number
- type Pair
- type Slice
- func Difference[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
- func FromMap[K comparable, V any](m map[K]V) Slice[Pair[K, V]]
- func Intersect[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
- func New[T any](items []T) Slice[T]
- func SymmetricDifference[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
- func Times[T any](count int, fn func(int) T) Slice[T]
- func Union[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
- func UniqueComparable[S ~[]T, T comparable](c S) Slice[T]
- func (c Slice[T]) After(pred func(T) bool) Slice[T]
- func (c Slice[T]) All(fn func(T) bool) bool
- func (c Slice[T]) Any(fn func(T) bool) bool
- func (c Slice[T]) At(i int) (T, bool)
- func (c Slice[T]) Chunk(size int) [][]T
- func (c Slice[T]) Clone() Slice[T]
- func (c Slice[T]) Concat(values ...[]T) Slice[T]
- func (c Slice[T]) CountBy[K comparable](keyFn func(T) K) map[K]int
- func (c Slice[T]) Dd()
- func (c Slice[T]) Dump() Slice[T]
- func (c Slice[T]) DumpStr() string
- func (c Slice[T]) Each(fn func(T)) Slice[T]
- func (c Slice[T]) Filter(fn func(T) bool) Slice[T]
- func (c Slice[T]) First() (value T, ok bool)
- func (c Slice[T]) FirstWhere(fn func(T) bool) (value T, ok bool)
- func (c Slice[T]) GroupBy[K comparable](keyFn func(T) K) map[K][]T
- func (c Slice[T]) IndexWhere(fn func(T) bool) (int, bool)
- func (c Slice[T]) Last() (value T, ok bool)
- func (c Slice[T]) LastWhere(fn func(T, int) bool) (value T, ok bool)
- func (c Slice[T]) Map[R any](fn func(T) R) Slice[R]
- func (c Slice[T]) MaxBy[K Number | ~string](keyFn func(T) K) (T, bool)
- func (c Slice[T]) MinBy[K Number | ~string](keyFn func(T) K) (T, bool)
- func (c Slice[T]) Multiply(n int) Slice[T]
- func (c Slice[T]) None(fn func(T) bool) bool
- func (c Slice[T]) Partition(fn func(T) bool) ([]T, []T)
- func (c Slice[T]) Prepend(values ...T) Slice[T]
- func (c Slice[T]) Reduce[R any](initial R, fn func(R, T) R) R
- func (c Slice[T]) Retain(fn func(T) bool) Slice[T]
- func (c Slice[T]) Reverse() Slice[T]
- func (c Slice[T]) Shuffle() Slice[T]
- func (c Slice[T]) Skip(n int) Slice[T]
- func (c Slice[T]) SkipLast(n int) Slice[T]
- func (c Slice[T]) Sort(less func(a, b T) bool) Slice[T]
- func (c Slice[T]) Take(n int) Slice[T]
- func (c Slice[T]) TakeLast(n int) Slice[T]
- func (c Slice[T]) TakeUntil(pred func(T) bool) Slice[T]
- func (c Slice[T]) Tap(fn func(Slice[T])) Slice[T]
- func (c Slice[T]) ToMap[K comparable, V any](keyFn func(T) K, valueFn func(T) V) map[K]V
- func (c Slice[T]) Transform(fn func(T) T) Slice[T]
- func (c Slice[T]) Unique(eq func(a, b T) bool) Slice[T]
- func (c Slice[T]) UniqueBy[K comparable](keyFn func(T) K) Slice[T]
- func (c Slice[T]) Window(size int, step int) [][]T
- func (c Slice[T]) Zip[U any](values []U) []Pair[T, U]
- func (c Slice[T]) ZipWith[U, R any](other []U, fn func(T, U) R) Slice[R]
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Avg ¶
Avg returns the average of the numeric slice values as a float64. If the slice is empty, Avg returns 0. @group Aggregation @behavior readonly @chainable false @terminal true
Example: integers
collection.Dump(collection.Avg([]int{2, 4, 6}))
// 4.000000 #float64
Example: float
collection.Dump(collection.Avg([]float64{1.5, 2.5, 3.0}))
// 2.333333 #float64
func CountByValue ¶
func CountByValue[S ~[]T, T comparable](c S) map[T]int
CountByValue returns the number of occurrences of each distinct item in c. @group Aggregation @behavior readonly @chainable false @terminal true
T must be comparable.
Example: strings
collection.Dump(collection.CountByValue([]string{"go", "forj", "go"}))
// #map[string]int {
// forj => 1 #int
// go => 2 #int
// }
func Dump ¶
func Dump(vs ...any)
Dump is a convenience function that calls godump.Dump. @group Debugging @behavior readonly @chainable false @terminal true
Example: integers
collection.Dump(collection.New([]int{1, 2, 3}))
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// ]
func Max ¶
Max returns the largest item in a numeric slice. The second return value is false if the slice is empty. @group Aggregation @behavior readonly @chainable false @terminal true
Example: integers
values := []int{3, 1, 2}
max1, ok1 := collection.Max(values)
collection.Dump(max1, ok1)
// 3 #int
// true #bool
Example: floats
values2 := []float64{1.5, 9.2, 4.4}
max2, ok2 := collection.Max(values2)
collection.Dump(max2, ok2)
// 9.200000 #float64
// true #bool
Example: empty numeric slice
empty := []int{}
max3, ok3 := collection.Max(empty)
collection.Dump(max3, ok3)
// 0 #int
// false #bool
func Median ¶
Median returns the statistical median of a numeric slice as float64. It returns (0, false) if the slice is empty. Median copies the input before sorting, so it allocates O(n) storage and does not mutate the input slice. @group Aggregation @behavior readonly @chainable false @terminal true
- Odd count: middle value. - Even count: average of the two middle values.
Example: integers - odd number of items
values := []int{3, 1, 2}
median1, ok1 := collection.Median(values)
collection.Dump(median1, ok1)
// 2.000000 #float64
// true #bool
Example: integers - even number of items
values2 := []int{10, 2, 4, 6}
median2, ok2 := collection.Median(values2)
collection.Dump(median2, ok2)
// 5.000000 #float64
// true #bool
Example: floats
values3 := []float64{1.1, 9.9, 3.3}
median3, ok3 := collection.Median(values3)
collection.Dump(median3, ok3)
// 3.300000 #float64
// true #bool
Example: integers - empty numeric slice
empty := []int{}
median4, ok4 := collection.Median(empty)
collection.Dump(median4, ok4)
// 0.000000 #float64
// false #bool
func Min ¶
Min returns the smallest item in a numeric slice. The second return value is false if the slice is empty. @group Aggregation @behavior readonly @chainable false @terminal true
Example: integers
values := []int{3, 1, 2}
min, ok := collection.Min(values)
collection.Dump(min, ok)
// 1 #int
// true #bool
Example: floats
values2 := []float64{2.5, 9.1, 1.2}
min2, ok2 := collection.Min(values2)
collection.Dump(min2, ok2)
// 1.200000 #float64
// true #bool
Example: integers - empty collection
empty := []int{}
min3, ok3 := collection.Min(empty)
collection.Dump(min3, ok3)
// 0 #int
// false #bool
func Mode ¶
func Mode[S ~[]T, T Number](items S) []T
Mode returns the most frequent numeric value or values in a slice. If multiple values tie for highest frequency, all are returned in first-seen order. @group Aggregation @behavior readonly @chainable false @terminal true
Example: integers - single mode
collection.Dump(collection.Mode([]int{1, 2, 2, 3}))
// #[]int [
// 0 => 2 #int
// ]
Example: integers - tie for mode
collection.Dump(collection.Mode([]int{1, 2, 1, 2}))
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// ]
Example: floats
collection.Dump(collection.Mode([]float64{1.1, 2.2, 1.1, 3.3}))
// #[]float64 [
// 0 => 1.100000 #float64
// ]
Example: integers - empty collection
collection.Dump(collection.Mode([]int{}))
// []int(nil)
func Sum ¶
func Sum[S ~[]T, T Number](s S) T
Sum returns the sum of all items in a numeric slice. If the slice is empty, Sum returns the zero value of T. @group Aggregation @behavior readonly @chainable false @terminal true
Example: integers
collection.Dump(collection.Sum([]int{1, 2, 3}))
// 6 #int
Example: floats
collection.Dump(collection.Sum([]float64{1.5, 2.5}))
// 4.000000 #float64
Example: integers - empty collection
collection.Dump(collection.Sum([]int{}))
// 0 #int
Types ¶
type Number ¶
type Number interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~float32 | ~float64
}
Number is a constraint that permits any numeric type.
type Slice ¶
type Slice[T any] []T
Slice is a named slice with fluent collection operations.
Because Slice is slice-backed, Go's built-in len, index, and range operations work directly on it. New borrows the supplied slice; use Clone when subsequent mutations must not share its backing array.
func Difference ¶
func Difference[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
Difference returns a new collection containing elements from the first collection that are not present in the second. Order follows the first collection, and duplicates are removed. @group Set Operations @behavior immutable @chainable true @terminal false
Example: integers
a := collection.New([]int{1, 2, 2, 3, 4})
b := collection.New([]int{2, 4})
collection.Dump(collection.Difference(a, b))
// #[]int [
// 0 => 1 #int
// 1 => 3 #int
// ]
Example: strings
left := collection.New([]string{"apple", "banana", "cherry"})
right := collection.New([]string{"banana"})
collection.Dump(collection.Difference(left, right))
// #[]string [
// 0 => "apple" #string
// 1 => "cherry" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
groupA := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Carol"},
})
groupB := collection.New([]User{
{ID: 2, Name: "Bob"},
})
collection.Dump(collection.Difference(groupA, groupB))
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 3 #int
// +Name => "Carol" #string
// }
// ]
func FromMap ¶
func FromMap[K comparable, V any](m map[K]V) Slice[Pair[K, V]]
FromMap materializes a map into a collection of key/value pairs. @group Maps @behavior immutable @chainable true @terminal false
The iteration order of the resulting collection is unspecified, matching Go's map iteration semantics.
This function does not mutate the input map.
Example: basic usage
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
c := collection.FromMap(m)
c.Sort(func(a, b collection.Pair[string, int]) bool {
return a.First < b.First
})
collection.Dump(c)
// #[]collection.Pair[string,int] [
// 0 => #collection.Pair[string,int] {
// +First => "a" #string
// +Second => 1 #int
// }
// 1 => #collection.Pair[string,int] {
// +First => "b" #string
// +Second => 2 #int
// }
// 2 => #collection.Pair[string,int] {
// +First => "c" #string
// +Second => 3 #int
// }
// ]
Example: filtering map entries
type Config struct {
Enabled bool
Timeout int
}
configs := map[string]Config{
"router-1": {Enabled: true, Timeout: 30},
"router-2": {Enabled: false, Timeout: 10},
"router-3": {Enabled: true, Timeout: 45},
}
out := collection.
FromMap(configs).
Filter(func(p collection.Pair[string, Config]) bool {
return p.Second.Enabled
}).
Sort(func(a, b collection.Pair[string, Config]) bool {
return a.First < b.First
})
collection.Dump(out)
// #[]collection.Pair[string,main.Config·1] [
// 0 => #collection.Pair[string,main.Config·1] {
// +First => "router-1" #string
// +Second => #main.Config {
// +Enabled => true #bool
// +Timeout => 30 #int
// }
// }
// 1 => #collection.Pair[string,main.Config·1] {
// +First => "router-3" #string
// +Second => #main.Config {
// +Enabled => true #bool
// +Timeout => 45 #int
// }
// }
// ]
func Intersect ¶
func Intersect[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
Intersect returns a new collection containing elements from the second collection that are also present in the first. @group Set Operations @behavior immutable @chainable true @terminal false
Order follows the second collection. Duplicates are preserved based on the second collection.
Example: integers
a := collection.New([]int{1, 2, 2, 3, 4})
b := collection.New([]int{2, 4, 4, 5})
collection.Dump(collection.Intersect(a, b))
// #[]int [
// 0 => 2 #int
// 1 => 4 #int
// 2 => 4 #int
// ]
Example: strings
left := collection.New([]string{"apple", "banana", "cherry"})
right := collection.New([]string{"banana", "date", "cherry", "banana"})
collection.Dump(collection.Intersect(left, right))
// #[]string [
// 0 => "banana" #string
// 1 => "cherry" #string
// 2 => "banana" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
groupA := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Carol"},
})
groupB := collection.New([]User{
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Carol"},
{ID: 4, Name: "Dave"},
})
collection.Dump(collection.Intersect(groupA, groupB))
// #[]main.User [
// 0 => #main.User {
// +ID => 2 #int
// +Name => "Bob" #string
// }
// 1 => #main.User {
// +ID => 3 #int
// +Name => "Carol" #string
// }
// ]
func New ¶
New creates a Slice from items and borrows their backing array. @group Construction @behavior immutable @chainable true @terminal false
Example: native slice operations
values := collection.New([]int{10, 20, 30})
fmt.Println(len(values))
// 3
fmt.Println(values[1])
// 20
total := 0
for _, value := range values {
total += value
}
fmt.Println(total)
// 60
func SymmetricDifference ¶
func SymmetricDifference[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
SymmetricDifference returns a new collection containing elements that appear in exactly one of the two collections. Order follows the first collection for its unique items, then the second for its unique items. Duplicates are removed. @group Set Operations @behavior immutable @chainable true @terminal false
Example: integers
a := collection.New([]int{1, 2, 3, 3})
b := collection.New([]int{3, 4, 4, 5})
collection.Dump(collection.SymmetricDifference(a, b))
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 4 #int
// 3 => 5 #int
// ]
Example: strings
left := collection.New([]string{"apple", "banana"})
right := collection.New([]string{"banana", "date"})
collection.Dump(collection.SymmetricDifference(left, right))
// #[]string [
// 0 => "apple" #string
// 1 => "date" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
groupA := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
})
groupB := collection.New([]User{
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Carol"},
})
collection.Dump(collection.SymmetricDifference(groupA, groupB))
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 3 #int
// +Name => "Carol" #string
// }
// ]
func Times ¶
Times creates a new collection by calling fn(i) for i = 1..count. This mirrors Laravel's Collection::times(), which is 1-indexed. @group Transformation @behavior immutable @chainable true @terminal false
If count <= 0, an empty collection is returned.
Example: integers - double each index
cTimes1 := collection.Times(5, func(i int) int {
return i * 2
})
collection.Dump(cTimes1)
// #[]int [
// 0 => 2 #int
// 1 => 4 #int
// 2 => 6 #int
// 3 => 8 #int
// 4 => 10 #int
// ]
Example: strings
cTimes2 := collection.Times(3, func(i int) string {
return fmt.Sprintf("item-%d", i)
})
collection.Dump(cTimes2)
// #[]string [
// 0 => "item-1" #string
// 1 => "item-2" #string
// 2 => "item-3" #string
// ]
Example: structs
type Point struct {
X int
Y int
}
cTimes3 := collection.Times(4, func(i int) Point {
return Point{X: i, Y: i * i}
})
collection.Dump(cTimes3)
// #[]main.Point [
// 0 => #main.Point {
// +X => 1 #int
// +Y => 1 #int
// }
// 1 => #main.Point {
// +X => 2 #int
// +Y => 4 #int
// }
// 2 => #main.Point {
// +X => 3 #int
// +Y => 9 #int
// }
// 3 => #main.Point {
// +X => 4 #int
// +Y => 16 #int
// }
// ]
func Union ¶
func Union[S1 ~[]T, S2 ~[]T, T comparable](a S1, b S2) Slice[T]
Union returns a new collection containing the unique elements from both collections. Items from the first collection are kept in order, followed by items from the second that were not already present. @group Set Operations @behavior immutable @chainable true @terminal false
Example: integers
a := collection.New([]int{1, 2, 2, 3})
b := collection.New([]int{3, 4, 4, 5})
collection.Dump(collection.Union(a, b))
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// 3 => 4 #int
// 4 => 5 #int
// ]
Example: strings
left := collection.New([]string{"apple", "banana"})
right := collection.New([]string{"banana", "date"})
collection.Dump(collection.Union(left, right))
// #[]string [
// 0 => "apple" #string
// 1 => "banana" #string
// 2 => "date" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
groupA := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
})
groupB := collection.New([]User{
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Carol"},
})
collection.Dump(collection.Union(groupA, groupB))
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 2 #int
// +Name => "Bob" #string
// }
// 2 => #main.User {
// +ID => 3 #int
// +Name => "Carol" #string
// }
// ]
func UniqueComparable ¶
func UniqueComparable[S ~[]T, T comparable](c S) Slice[T]
UniqueComparable returns a new collection with duplicate comparable items removed. The first occurrence of each value is kept, and order is preserved. It uses a map to track seen values, so it has expected linear time and allocates storage for both the map and the result. @group Set Operations @behavior immutable @chainable true @terminal false
Example: integers
collection.Dump(collection.UniqueComparable([]int{1, 2, 2, 3, 4, 4, 5}))
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// 3 => 4 #int
// 4 => 5 #int
// ]
Example: strings
collection.Dump(collection.UniqueComparable([]string{"A", "a", "B", "B"}))
// #[]string [
// 0 => "A" #string
// 1 => "a" #string
// 2 => "B" #string
// ]
func (Slice[T]) After ¶
After returns all items after the first element for which pred returns true. If no element matches, an empty collection is returned. @group Ordering @behavior immutable @chainable true @terminal false
NOTE: returns a view (shares backing array). Use Clone() to detach.
Example: integers
collection.New([]int{1, 2, 3, 4, 5}).After(func(v int) bool { return v == 3 }).Dump()
// #[]int [
// 0 => 4 #int
// 1 => 5 #int
// ]
func (Slice[T]) All ¶
All returns true if fn returns true for every item in the collection. If the collection is empty, All returns true (vacuously true). @group Querying @behavior readonly @chainable false @terminal true
Example: integers - all even
collection.Dump(collection.New([]int{2, 4, 6}).All(func(v int) bool { return v%2 == 0 }))
// true #bool
Example: integers - not all even
collection.Dump(collection.New([]int{2, 3, 4}).All(func(v int) bool { return v%2 == 0 }))
// false #bool
Example: strings - all non-empty
collection.Dump(collection.New([]string{"a", "b", "c"}).All(func(s string) bool { return s != "" }))
// true #bool
Example: empty collection (vacuously true)
collection.Dump(collection.New([]int{}).All(func(v int) bool { return v > 0 }))
// true #bool
func (Slice[T]) Any ¶
Any returns true if at least one item satisfies fn. @group Querying @behavior readonly @chainable false @terminal true Example: integers
collection.Dump(collection.New([]int{1, 2, 3, 4}).Any(func(v int) bool { return v%2 == 0 }))
// true #bool
func (Slice[T]) At ¶
At returns the item at the given index and a boolean indicating whether the index was within bounds. @group Querying @behavior readonly @chainable false @terminal true
This method is safe and does not panic for out-of-range indices.
Example: integers
c := collection.New([]int{10, 20, 30})
v, ok := c.At(1)
collection.Dump(v, ok)
// 20 #int
// true #bool
Example: out of bounds
v2, ok2 := c.At(10) collection.Dump(v2, ok2) // 0 #int // false #bool
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
})
u, ok3 := users.At(0)
collection.Dump(u, ok3)
// #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// true #bool
func (Slice[T]) Chunk ¶
Chunk splits the collection into chunks of the given size. The final chunk may be smaller if len(items) is not divisible by size. @group Slicing @behavior readonly @chainable false @terminal true
If size <= 0, nil is returned.
Chunk allocates the outer result slice. Each chunk is a capacity-capped view that shares the backing array with the source collection. Example: integers
collection.Dump(collection.New([]int{1, 2, 3, 4, 5}).Chunk(2))
// #[][]int [
// 0 => #[]int [
// 0 => 1 #int
// 1 => 2 #int
// ]
// 1 => #[]int [
// 0 => 3 #int
// 1 => 4 #int
// ]
// 2 => #[]int [
// 0 => 5 #int
// ]
//]
Example: structs
type User struct {
ID int
Name string
}
users := []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Carol"},
{ID: 4, Name: "Dave"},
}
userChunks := collection.New(users).Chunk(2)
collection.Dump(userChunks)
// #[][]main.User [
// 0 => #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 2 #int
// +Name => "Bob" #string
// }
// ]
// 1 => #[]main.User [
// 0 => #main.User {
// +ID => 3 #int
// +Name => "Carol" #string
// }
// 1 => #main.User {
// +ID => 4 #int
// +Name => "Dave" #string
// }
// ]
//]
func (Slice[T]) Clone ¶
Clone returns a copy of the collection.
The returned collection has its own backing slice, so element assignments and slice operations on the clone do not affect the original collection. Clone is shallow: pointers, maps, slices, and other references stored in elements remain shared.
Clone is intended to be used when branching a pipeline while preserving the original collection.
@group Construction @behavior immutable @chainable true @terminal false
Example: basic cloning
c := collection.New([]int{1, 2, 3})
clone := c.Clone()
clone.Transform(func(value int) int { return value * 10 })
collection.Dump(c)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// ]
collection.Dump(clone)
// #[]int [
// 0 => 10 #int
// 1 => 20 #int
// 2 => 30 #int
// ]
Example: branching pipelines
base := collection.New([]int{1, 2, 3, 4, 5})
evens := base.Clone().Retain(func(v int) bool {
return v%2 == 0
})
odds := base.Clone().Retain(func(v int) bool {
return v%2 != 0
})
collection.Dump(base)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// 3 => 4 #int
// 4 => 5 #int
// ]
collection.Dump(evens)
// #[]int [
// 0 => 2 #int
// 1 => 4 #int
// ]
collection.Dump(odds)
// #[]int [
// 0 => 1 #int
// 1 => 3 #int
// 2 => 5 #int
// ]
func (Slice[T]) Concat ¶
Concat returns an independent collection containing c followed by values. @group Transformation @behavior immutable @chainable true @terminal false
Callers must capture the returned Slice because a value receiver cannot extend c's slice header. The returned collection never shares backing storage with c.
Example: strings
c := collection.New([]string{"John Doe"})
concatenated := c.
Concat([]string{"Jane Doe"}).
Concat([]string{"Johnny Doe"})
collection.Dump(concatenated)
// #[]string [
// 0 => "John Doe" #string
// 1 => "Jane Doe" #string
// 2 => "Johnny Doe" #string
// ]
Example: spare capacity
backing := make([]int, 2, 4)
copy(backing, []int{1, 2})
values := collection.New(backing)
values = values.Concat([]int{3, 4})
fmt.Println(values)
// [1 2 3 4]
func (Slice[T]) CountBy ¶
func (c Slice[T]) CountBy[K comparable](keyFn func(T) K) map[K]int
CountBy returns occurrence counts keyed by the extracted value. @group Aggregation @behavior readonly @chainable false @terminal true
Example: count integers by parity
numbers := collection.New([]int{1, 2, 3, 5})
counts := numbers.CountBy(func(number int) string {
if number%2 == 0 {
return "even"
}
return "odd"
})
collection.Dump(counts)
// #map[string]int {
// even => 1 #int
// odd => 3 #int
// }
func (Slice[T]) Dd ¶
func (c Slice[T]) Dd()
Dd prints items then terminates execution. Like Laravel's dd(), this is intended for debugging and should not be used in production control flow. @group Debugging @behavior readonly @chainable false @terminal true
This method never returns.
Example: strings
collection.New([]string{"a", "b"}).Dd()
// #[]string [
// 0 => "a" #string
// 1 => "b" #string
// ]
// Process finished with the exit code 1
func (Slice[T]) Dump ¶
Dump prints items with godump and returns the same collection. This is a no-op on the collection itself. @group Debugging @behavior readonly @chainable true @terminal false
Example: integers
collection.New([]int{1, 2, 3}).Dump()
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// ]
Example: integers - chaining
collection.New([]int{1, 2, 3}).
Filter(func(v int) bool { return v > 1 }).
Dump()
// #[]int [
// 0 => 2 #int
// 1 => 3 #int
// ]
func (Slice[T]) DumpStr ¶
DumpStr returns the pretty-printed dump of the items as a string, without printing or exiting. Useful for logging, snapshot testing, and non-interactive debugging. @group Debugging @behavior readonly @chainable false @terminal true
Example: integers
fmt.Println(collection.New([]int{10, 20}).DumpStr())
// #[]int [
// 0 => 10 #int
// 1 => 20 #int
// ]
func (Slice[T]) Each ¶
Each runs fn for every item in the collection and returns the same collection, so it can be used in chains for side effects (logging, debugging, etc.). @group Transformation @behavior readonly @chainable true @terminal false
Example: integers
c := collection.New([]int{1, 2, 3})
sum := 0
c.Each(func(v int) {
sum += v
})
collection.Dump(sum)
// 6 #int
Example: strings
c2 := collection.New([]string{"apple", "banana", "cherry"})
var out []string
c2.Each(func(s string) {
out = append(out, strings.ToUpper(s))
})
collection.Dump(out)
// #[]string [
// 0 => "APPLE" #string
// 1 => "BANANA" #string
// 2 => "CHERRY" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Charlie"},
})
var names []string
users.Each(func(u User) {
names = append(names, u.Name)
})
collection.Dump(names)
// #[]string [
// 0 => "Alice" #string
// 1 => "Bob" #string
// 2 => "Charlie" #string
// ]
func (Slice[T]) Filter ¶
Filter keeps only the elements for which fn returns true.
Filter allocates a new Slice and leaves c and its backing storage unchanged. @group Slicing @behavior immutable @chainable true @terminal false Example: integers
source := collection.New([]int{1, 2, 3, 4})
filtered := source.Filter(func(v int) bool {
return v%2 == 0
})
collection.Dump(filtered)
// #[]int [
// 0 => 2 #int
// 1 => 4 #int
// ]
fmt.Println(source[0])
// 1
Example: strings
c2 := collection.New([]string{"apple", "banana", "cherry", "avocado"})
c2 = c2.Filter(func(v string) bool {
return strings.HasPrefix(v, "a")
})
collection.Dump(c2)
// #[]string [
// 0 => "apple" #string
// 1 => "avocado" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Andrew"},
{ID: 4, Name: "Carol"},
})
users = users.Filter(func(u User) bool {
return strings.HasPrefix(u.Name, "A")
})
collection.Dump(users)
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 3 #int
// +Name => "Andrew" #string
// }
// ]
func (Slice[T]) First ¶
First returns the first element in the collection. If the collection is empty, ok will be false. @group Querying @behavior readonly @chainable false @terminal true
Example: integers
c := collection.New([]int{10, 20, 30})
v, ok := c.First()
collection.Dump(v, ok)
// 10 #int
// true #bool
Example: strings
c2 := collection.New([]string{"alpha", "beta", "gamma"})
v2, ok2 := c2.First()
collection.Dump(v2, ok2)
// "alpha" #string
// true #bool
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
})
u, ok3 := users.First()
collection.Dump(u, ok3)
// #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// true #bool
Example: integers - empty collection
c3 := collection.New([]int{})
v3, ok4 := c3.First()
collection.Dump(v3, ok4)
// 0 #int
// false #bool
func (Slice[T]) FirstWhere ¶
FirstWhere returns the first item in the collection for which the provided predicate function returns true. If no items match, ok=false is returned along with the zero value of T. @group Querying @behavior readonly @chainable false @terminal true
This method is equivalent to Laravel's collection->first(fn) and mirrors the behavior found in functional collections in other languages.
Example: integers
nums := collection.New([]int{1, 2, 3, 4, 5})
v, ok := nums.FirstWhere(func(n int) bool {
return n%2 == 0
})
collection.Dump(v, ok)
// 2 #int
// true #bool
v, ok = nums.FirstWhere(func(n int) bool {
return n > 10
})
collection.Dump(v, ok)
// 0 #int
// false #bool
func (Slice[T]) GroupBy ¶
func (c Slice[T]) GroupBy[K comparable](keyFn func(T) K) map[K][]T
GroupBy partitions this Slice into independent built-in slices keyed by the extracted value. @group Grouping @behavior readonly @chainable false @terminal true
Example: group integers by parity
numbers := collection.New([]int{1, 2, 3, 4})
groups := numbers.GroupBy(func(number int) string {
if number%2 == 0 {
return "even"
}
return "odd"
})
collection.Dump(groups["even"], groups["odd"])
// #[]int [
// 0 => 2 #int
// 1 => 4 #int
// ]
// #[]int [
// 0 => 1 #int
// 1 => 3 #int
// ]
fmt.Println(len(groups["even"]))
// 2
fmt.Println(groups["odd"][0])
// 1
collection.Dump(groups["even"][:1])
// #[]int [
// 0 => 2 #int
// ]
func (Slice[T]) IndexWhere ¶
IndexWhere returns the index of the first item in the collection for which the provided predicate function returns true. If no item matches, it returns (0, false). @group Querying @behavior readonly @chainable false @terminal true
This operation performs no allocations and short-circuits on the first match.
Example: integers
c := collection.New([]int{10, 20, 30, 40})
idx, ok := c.IndexWhere(func(v int) bool { return v == 30 })
collection.Dump(idx, ok)
// 2 #int
// true #bool
Example: not found
idx2, ok2 := c.IndexWhere(func(v int) bool { return v == 99 })
collection.Dump(idx2, ok2)
// 0 #int
// false #bool
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Carol"},
})
idx3, ok3 := users.IndexWhere(func(u User) bool {
return u.Name == "Bob"
})
collection.Dump(idx3, ok3)
// 1 #int
// true #bool
func (Slice[T]) Last ¶
Last returns the last element in the collection. If the collection is empty, ok will be false. @group Querying @behavior readonly @chainable false @terminal true
Example: integers
c := collection.New([]int{10, 20, 30})
v, ok := c.Last()
collection.Dump(v, ok)
// 30 #int
// true #bool
Example: strings
c2 := collection.New([]string{"alpha", "beta", "gamma"})
v2, ok2 := c2.Last()
collection.Dump(v2, ok2)
// "gamma" #string
// true #bool
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Charlie"},
})
u, ok3 := users.Last()
collection.Dump(u, ok3)
// #main.User {
// +ID => 3 #int
// +Name => "Charlie" #string
// }
// true #bool
Example: empty collection
c3 := collection.New([]int{})
v3, ok4 := c3.Last()
collection.Dump(v3, ok4)
// 0 #int
// false #bool
func (Slice[T]) LastWhere ¶
LastWhere returns the last element in the collection that satisfies the predicate fn. If fn is nil, LastWhere returns the final element in the underlying slice. If the collection is empty or no element matches, ok will be false. @group Querying @behavior readonly @chainable false @terminal true
Example: integers
c := collection.New([]int{1, 2, 3, 4})
v, ok := c.LastWhere(func(v int, i int) bool {
return v < 3
})
collection.Dump(v, ok)
// 2 #int
// true #bool
Example: integers without predicate (equivalent to Last())
c2 := collection.New([]int{10, 20, 30, 40})
v2, ok2 := c2.LastWhere(nil)
collection.Dump(v2, ok2)
// 40 #int
// true #bool
Example: strings
c3 := collection.New([]string{"alpha", "beta", "gamma", "delta"})
v3, ok3 := c3.LastWhere(func(s string, i int) bool {
return strings.HasPrefix(s, "g")
})
collection.Dump(v3, ok3)
// "gamma" #string
// true #bool
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 3, Name: "Alex"},
{ID: 4, Name: "Brian"},
})
u, ok4 := users.LastWhere(func(u User, i int) bool {
return strings.HasPrefix(u.Name, "A")
})
collection.Dump(u, ok4)
// #main.User {
// +ID => 3 #int
// +Name => "Alex" #string
// }
// true #bool
Example: no matching element
c4 := collection.New([]int{5, 6, 7})
v4, ok5 := c4.LastWhere(func(v int, i int) bool {
return v > 10
})
collection.Dump(v4, ok5)
// 0 #int
// false #bool
Example: empty collection
c5 := collection.New([]int{})
v5, ok6 := c5.LastWhere(nil)
collection.Dump(v5, ok6)
// 0 #int
// false #bool
func (Slice[T]) Map ¶
Map maps this Slice to a newly allocated Slice with a potentially different element type. @group Transformation @behavior immutable @chainable true @terminal false
Example: map integers to labels
numbers := collection.New([]int{1, 2, 3, 4})
labels := numbers.Map(func(number int) string {
if number%2 == 0 {
return "even"
}
return "odd"
})
collection.Dump(labels)
// #[]string [
// 0 => "odd" #string
// 1 => "even" #string
// 2 => "odd" #string
// 3 => "even" #string
// ]
fmt.Println(numbers[0])
// 1
func (Slice[T]) MaxBy ¶
MaxBy returns the item whose extracted key is the largest. @group Aggregation @behavior readonly @chainable false @terminal true
Example: longest string
words := collection.New([]string{"pear", "fig", "banana"})
longest, ok := words.MaxBy(func(word string) int {
return len(word)
})
collection.Dump(longest, ok)
// "banana" #string
// true #bool
func (Slice[T]) MinBy ¶
MinBy returns the item whose extracted key is the smallest. @group Aggregation @behavior readonly @chainable false @terminal true
Example: shortest string
words := collection.New([]string{"pear", "fig", "banana"})
shortest, ok := words.MinBy(func(word string) int {
return len(word)
})
collection.Dump(shortest, ok)
// "fig" #string
// true #bool
func (Slice[T]) Multiply ¶
Multiply creates `n` copies of all items in the collection and returns a new collection. @group Transformation @behavior immutable @chainable true @terminal false
Example: integers
ints := collection.New([]int{1, 2})
collection.Dump(ints.Multiply(3))
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 1 #int
// 3 => 2 #int
// 4 => 1 #int
// 5 => 2 #int
// ]
Example: strings
collection.Dump(collection.New([]string{"a", "b"}).Multiply(2))
// #[]string [
// 0 => "a" #string
// 1 => "b" #string
// 2 => "a" #string
// 3 => "b" #string
// ]
Example: structs
type User struct {
Name string
}
users := collection.New([]User{{Name: "Alice"}, {Name: "Bob"}})
collection.Dump(users.Multiply(2))
// #[]main.User [
// 0 => #main.User {
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +Name => "Bob" #string
// }
// 2 => #main.User {
// +Name => "Alice" #string
// }
// 3 => #main.User {
// +Name => "Bob" #string
// }
// ]
Example: multiplying by zero or negative returns empty
collection.Dump(ints.Multiply(0)) // #[]int [ // ]
func (Slice[T]) None ¶
None returns true if fn returns false for every item in the collection. If the collection is empty, None returns true. @group Querying @behavior readonly @chainable false @terminal true
Example: integers - none even
collection.Dump(collection.New([]int{1, 3, 5}).None(func(v int) bool { return v%2 == 0 }))
// true #bool
Example: integers - some even
collection.Dump(collection.New([]int{1, 2, 3}).None(func(v int) bool { return v%2 == 0 }))
// false #bool
Example: empty collection
collection.Dump(collection.New([]int{}).None(func(v int) bool { return v > 0 }))
// true #bool
func (Slice[T]) Partition ¶
Partition splits the collection into two new slices based on predicate fn. The first slice contains items where fn returns true; the second contains items where fn returns false. Order is preserved within each partition. @group Slicing @behavior immutable @chainable false @terminal true
Example: integers - even/odd
nums := collection.New([]int{1, 2, 3, 4, 5})
evens, odds := nums.Partition(func(n int) bool {
return n%2 == 0
})
collection.Dump(evens, odds)
// #[]int [
// 0 => 2 #int
// 1 => 4 #int
// ]
// #[]int [
// 0 => 1 #int
// 1 => 3 #int
// 2 => 5 #int
// ]
Example: strings - prefix match
words := collection.New([]string{"go", "gopher", "rust", "ruby"})
goWords, other := words.Partition(func(s string) bool {
return strings.HasPrefix(s, "go")
})
collection.Dump(goWords, other)
// #[]string [
// 0 => "go" #string
// 1 => "gopher" #string
// ]
// #[]string [
// 0 => "rust" #string
// 1 => "ruby" #string
// ]
Example: structs - active vs inactive
type User struct {
Name string
Active bool
}
users := collection.New([]User{
{Name: "Alice", Active: true},
{Name: "Bob", Active: false},
{Name: "Carol", Active: true},
})
active, inactive := users.Partition(func(u User) bool {
return u.Active
})
collection.Dump(active, inactive)
// #[]main.User [
// 0 => #main.User {
// +Name => "Alice" #string
// +Active => true #bool
// }
// 1 => #main.User {
// +Name => "Carol" #string
// +Active => true #bool
// }
// ]
// #[]main.User [
// 0 => #main.User {
// +Name => "Bob" #string
// +Active => false #bool
// }
// ]
func (Slice[T]) Prepend ¶
Prepend returns an independently backed Slice containing values followed by c. @group Transformation @behavior immutable @chainable true @terminal false
It allocates exactly enough storage for the result and leaves c unchanged.
Example: integers
c := collection.New([]int{3, 4})
result := c.Prepend(1, 2)
collection.Dump(result)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// 3 => 4 #int
// ]
Example: strings
letters := collection.New([]string{"c", "d"})
result2 := letters.Prepend("a", "b")
collection.Dump(result2)
// #[]string [
// 0 => "a" #string
// 1 => "b" #string
// 2 => "c" #string
// 3 => "d" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 2, Name: "Bob"},
})
result3 := users.Prepend(User{ID: 1, Name: "Alice"})
collection.Dump(result3)
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 2 #int
// +Name => "Bob" #string
// }
// ]
Example: integers - Prepending into an empty collection
empty := collection.New([]int{})
result4 := empty.Prepend(9, 8)
collection.Dump(result4)
// #[]int [
// 0 => 9 #int
// 1 => 8 #int
// ]
Example: integers - Prepending no values → no change
c2 := collection.New([]int{1, 2})
result5 := c2.Prepend()
collection.Dump(result5)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// ]
func (Slice[T]) Reduce ¶
Reduce collapses the collection into a single accumulated value. The accumulator may have a different type R from the collection's elements. @group Aggregation @behavior readonly @chainable false @terminal true
This is useful for computing sums, concatenations, aggregates, or any fold-style reduction.
Example: integers - sum
sum := collection.New([]int{1, 2, 3}).Reduce(0, func(acc, n int) int {
return acc + n
})
collection.Dump(sum)
// 6 #int
Example: strings
joined := collection.New([]string{"a", "b", "c"}).Reduce("", func(acc, s string) string {
return acc + s
})
collection.Dump(joined)
// "abc" #string
Example: structs
type Stats struct {
Count int
Sum int
}
stats := collection.New([]Stats{
{Count: 1, Sum: 10},
{Count: 1, Sum: 20},
{Count: 1, Sum: 30},
})
total := stats.Reduce(Stats{}, func(acc, s Stats) Stats {
acc.Count += s.Count
acc.Sum += s.Sum
return acc
})
collection.Dump(total)
// #main.Stats {
// +Count => 3 #int
// +Sum => 60 #int
// }
func (Slice[T]) Retain ¶
Retain keeps items for which fn returns true in c's existing backing array. @group Slicing @behavior mutable @chainable true @terminal false
Retain returns a capacity-capped, shortened slice header, so callers should retain its result when subsequent operations must observe the new length.
Example: keep even integers without allocating another backing array
values := collection.New([]int{1, 2, 3, 4})
evens := values.Retain(func(value int) bool { return value%2 == 0 })
collection.Dump(evens)
// #[]int [
// 0 => 2 #int
// 1 => 4 #int
// ]
fmt.Println(values)
// [2 4 0 0]
func (Slice[T]) Reverse ¶
Reverse reverses the order of items in the collection in place and returns the same collection for chaining. @group Ordering @behavior mutable @chainable true @terminal false
This operation performs no allocations.
Example: integers
c := collection.New([]int{1, 2, 3, 4})
c.Reverse()
collection.Dump(c)
// #[]int [
// 0 => 4 #int
// 1 => 3 #int
// 2 => 2 #int
// 3 => 1 #int
// ]
Example: strings - chaining
out := collection.New([]string{"a", "b", "c"}).
Reverse().
Concat([]string{"d"})
collection.Dump(out)
// #[]string [
// 0 => "c" #string
// 1 => "b" #string
// 2 => "a" #string
// 3 => "d" #string
// ]
Example: structs
type User struct {
ID int
}
users := collection.New([]User{
{ID: 1},
{ID: 2},
{ID: 3},
})
users.Reverse()
collection.Dump(users)
// #[]main.User [
// 0 => #main.User {
// +ID => 3 #int
// }
// 1 => #main.User {
// +ID => 2 #int
// }
// 2 => #main.User {
// +ID => 1 #int
// }
// ]
func (Slice[T]) Shuffle ¶
Shuffle shuffles the collection in place and returns the same collection. @group Ordering @behavior mutable @chainable true @terminal false
This operation mutates the receiver's backing slice.
Example: integers
c := collection.New([]int{1, 2, 3, 4, 5})
c.Shuffle()
fmt.Println(len(c), collection.Sum(c))
// 5 15
Example: strings - chaining
out2 := collection.New([]string{"a", "b", "c"}).
Shuffle().
Concat([]string{"d"})
fmt.Println(len(out2))
// 4
Example: structs
type User struct {
ID int
}
users := collection.New([]User{
{ID: 1},
{ID: 2},
{ID: 3},
{ID: 4},
})
users.Shuffle()
fmt.Println(len(users))
// 4
func (Slice[T]) Skip ¶
Skip returns a new collection with the first n items skipped. If n is less than or equal to zero, Skip returns the full collection. If n is greater than or equal to the collection length, Skip returns an empty collection. @group Slicing @behavior immutable @chainable true @terminal false
This operation performs no element allocations; it re-slices the underlying slice.
NOTE: returns a view (shares backing array). Use Clone() to detach.
Example: integers
c := collection.New([]int{1, 2, 3, 4, 5})
out := c.Skip(2)
collection.Dump(out)
// #[]int [
// 0 => 3 #int
// 1 => 4 #int
// 2 => 5 #int
// ]
Example: skip none
out2 := c.Skip(0) collection.Dump(out2) // #[]int [ // 0 => 1 #int // 1 => 2 #int // 2 => 3 #int // 3 => 4 #int // 4 => 5 #int // ]
Example: skip all
out3 := c.Skip(10) collection.Dump(out3) // #[]int [ // ]
Example: structs
type User struct {
ID int
}
users := collection.New([]User{
{ID: 1},
{ID: 2},
{ID: 3},
})
out4 := users.Skip(1)
collection.Dump(out4)
// #[]main.User [
// 0 => #main.User {
// +ID => 2 #int
// }
// 1 => #main.User {
// +ID => 3 #int
// }
// ]
func (Slice[T]) SkipLast ¶
SkipLast returns a new collection with the last n items skipped. If n is less than or equal to zero, SkipLast returns the full collection. If n is greater than or equal to the collection length, SkipLast returns an empty collection. @group Slicing @behavior immutable @chainable true @terminal false
This operation performs no element allocations; it re-slices the underlying slice.
NOTE: returns a view (shares backing array). Use Clone() to detach.
Example: integers
c := collection.New([]int{1, 2, 3, 4, 5})
out := c.SkipLast(2)
collection.Dump(out)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// ]
Example: skip none
out2 := c.SkipLast(0) collection.Dump(out2) // #[]int [ // 0 => 1 #int // 1 => 2 #int // 2 => 3 #int // 3 => 4 #int // 4 => 5 #int // ]
Example: skip all
out3 := c.SkipLast(10) collection.Dump(out3) // #[]int [ // ]
Example: structs
type User struct {
ID int
}
users := collection.New([]User{
{ID: 1},
{ID: 2},
{ID: 3},
})
out4 := users.SkipLast(1)
collection.Dump(out4)
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// }
// 1 => #main.User {
// +ID => 2 #int
// }
// ]
func (Slice[T]) Sort ¶
Sort sorts the collection in place using the provided comparison function and returns the same collection for chaining. @group Ordering @behavior mutable @chainable true @terminal false
The comparison function `less(a, b)` should return true if `a` should come before `b` in the sorted order.
This operation mutates the underlying slice and does not allocate a new element backing slice. The underlying sort implementation may make small internal allocations.
Example: integers
c := collection.New([]int{5, 1, 4, 2})
c.Sort(func(a, b int) bool { return a < b })
collection.Dump(c)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 4 #int
// 3 => 5 #int
// ]
Example: strings (descending)
c2 := collection.New([]string{"apple", "banana", "cherry"})
c2.Sort(func(a, b string) bool { return a > b })
collection.Dump(c2)
// #[]string [
// 0 => "cherry" #string
// 1 => "banana" #string
// 2 => "apple" #string
// ]
Example: structs
type User struct {
Name string
Age int
}
users := collection.New([]User{
{Name: "Alice", Age: 30},
{Name: "Bob", Age: 25},
{Name: "Carol", Age: 40},
})
// Sort by age ascending
users.Sort(func(a, b User) bool {
return a.Age < b.Age
})
collection.Dump(users)
// #[]main.User [
// 0 => #main.User {
// +Name => "Bob" #string
// +Age => 25 #int
// }
// 1 => #main.User {
// +Name => "Alice" #string
// +Age => 30 #int
// }
// 2 => #main.User {
// +Name => "Carol" #string
// +Age => 40 #int
// }
// ]
func (Slice[T]) Take ¶
Take returns a capacity-capped view containing the first n items.
If n exceeds the collection length, the entire collection is returned. If n == 0, an empty collection is returned.
NOTE: returns a view (shares backing array). Use Clone() to detach.
@group Slicing @behavior immutable @chainable true @terminal false Example: integers - take first 3
c1 := collection.New([]int{0, 1, 2, 3, 4, 5})
out1 := c1.Take(3)
collection.Dump(out1)
// #[]int [
// 0 => 0 #int
// 1 => 1 #int
// 2 => 2 #int
// ]
Example: integers - n exceeds length → whole collection
c3 := collection.New([]int{10, 20})
out3 := c3.Take(10)
collection.Dump(out3)
// #[]int [
// 0 => 10 #int
// 1 => 20 #int
// ]
Example: integers - zero → empty
c4 := collection.New([]int{1, 2, 3})
out4 := c4.Take(0)
collection.Dump(out4)
// #[]int [
// ]
func (Slice[T]) TakeLast ¶
TakeLast returns a capacity-capped view containing the last n items. If n is less than or equal to zero, TakeLast returns an empty collection. If n is greater than or equal to the collection length, TakeLast returns the full collection.
This operation performs no element allocations; it re-slices the underlying slice.
NOTE: returns a view (shares backing array). Use Clone() to detach. @group Slicing @behavior immutable @chainable true @terminal false Example: integers
c := collection.New([]int{1, 2, 3, 4, 5})
out := c.TakeLast(2)
collection.Dump(out)
// #[]int [
// 0 => 4 #int
// 1 => 5 #int
// ]
Example: take none
out2 := c.TakeLast(0) collection.Dump(out2) // #[]int [ // ]
Example: take all
out3 := c.TakeLast(10) collection.Dump(out3) // #[]int [ // 0 => 1 #int // 1 => 2 #int // 2 => 3 #int // 3 => 4 #int // 4 => 5 #int // ]
Example: structs
type User struct {
ID int
}
users := collection.New([]User{
{ID: 1},
{ID: 2},
{ID: 3},
})
out4 := users.TakeLast(1)
collection.Dump(out4)
// #[]main.User [
// 0 => #main.User {
// +ID => 3 #int
// }
// ]
func (Slice[T]) TakeUntil ¶
TakeUntil returns items until the predicate function returns true. The matching item is NOT included. @group Slicing @behavior immutable @chainable true @terminal false
NOTE: returns a view (shares backing array). Use Clone() to detach. Example: integers - stop when value >= 3
c1 := collection.New([]int{1, 2, 3, 4})
out1 := c1.TakeUntil(func(v int) bool { return v >= 3 })
collection.Dump(out1)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// ]
Example: integers - predicate immediately true → empty result
c2 := collection.New([]int{10, 20, 30})
out2 := c2.TakeUntil(func(v int) bool { return v < 50 })
collection.Dump(out2)
// #[]int [
// ]
Example: integers - no match → full list returned
c3 := collection.New([]int{1, 2, 3})
out3 := c3.TakeUntil(func(v int) bool { return v == 99 })
collection.Dump(out3)
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// ]
func (Slice[T]) Tap ¶
Tap invokes fn with the Slice value for side effects such as logging, debugging, or inspection, then returns the Slice to allow chaining. @group Transformation @behavior mutable @chainable true @terminal false
The callback receives a borrowed Slice and may mutate its elements. Use Clone before Tap when the original backing array must remain isolated. The slice header is passed by value, so reslicing, appending, or assigning a shortened Slice inside fn does not change the header returned by Tap.
Example: integers - capture intermediate state during a chain
captured1 := []int{}
c1 := collection.New([]int{3, 1, 2}).
Sort(func(a, b int) bool { return a < b }). // → [1, 2, 3]
Tap(func(col collection.Slice[int]) {
captured1 = append([]int(nil), col...) // snapshot copy
}).
Filter(func(v int) bool { return v >= 2 }).
Dump()
// #[]int [
// 0 => 2 #int
// 1 => 3 #int
// ]
// Use BOTH variables so nothing is "declared and not used"
collection.Dump(c1)
collection.Dump(captured1)
// #[]int [
// 0 => 2 #int
// 1 => 3 #int
// ]
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// ]
Example: integers - tap for debugging without changing flow
c2 := collection.New([]int{10, 20, 30}).
Tap(func(col collection.Slice[int]) {
collection.Dump(col)
// #[]int [
// 0 => 10 #int
// 1 => 20 #int
// 2 => 30 #int
// ]
}).
Filter(func(v int) bool { return v > 10 })
collection.Dump(c2) // ensures c2 is used
// #[]int [
// 0 => 20 #int
// 1 => 30 #int
// ]
Example: structs - Tap with struct collection
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
})
users2 := users.Tap(func(col collection.Slice[User]) {
collection.Dump(col)
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 2 #int
// +Name => "Bob" #string
// }
// ]
})
collection.Dump(users2) // ensures users2 is used
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 2 #int
// +Name => "Bob" #string
// }
// ]
func (Slice[T]) ToMap ¶
func (c Slice[T]) ToMap[K comparable, V any](keyFn func(T) K, valueFn func(T) V) map[K]V
ToMap reduces this collection into a map using the provided key and value functions. If multiple items produce the same key, the value derived from the last item wins. @group Maps @behavior readonly @chainable false @terminal true
Example: index words by their value
words := collection.New([]string{"go", "forj"})
lengths := words.ToMap(
func(word string) string { return word },
func(word string) int { return len(word) },
)
collection.Dump(lengths)
// #map[string]int {
// forj => 4 #int
// go => 2 #int
// }
func (Slice[T]) Transform ¶
Transform applies a same-type transformation in place and returns the same collection. @group Transformation @behavior mutable @chainable true @terminal false
Transform mutates the receiver's backing slice. Use Clone() if you need isolation.
Example: integers
c := collection.New([]int{1, 2, 3})
c.Transform(func(v int) int {
return v * 10
})
collection.Dump(c)
// #[]int [
// 0 => 10 #int
// 1 => 20 #int
// 2 => 30 #int
// ]
Example: strings
c2 := collection.New([]string{"apple", "banana", "cherry"})
upper := c2.Transform(func(s string) string {
return strings.ToUpper(s)
})
collection.Dump(upper)
// #[]string [
// 0 => "APPLE" #string
// 1 => "BANANA" #string
// 2 => "CHERRY" #string
// ]
Example: structs
type User struct {
ID int
Name string
}
users := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
})
updated := users.Transform(func(u User) User {
u.Name = strings.ToUpper(u.Name)
return u
})
collection.Dump(updated)
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "ALICE" #string
// }
// 1 => #main.User {
// +ID => 2 #int
// +Name => "BOB" #string
// }
// ]
func (Slice[T]) Unique ¶
Unique returns a new collection with duplicate items removed, based on the equality function `eq`. The first occurrence of each unique value is kept, and order is preserved. @group Set Operations @behavior immutable @chainable true @terminal false
The `eq` function should return true when two values are considered equal.
Example: integers
c1 := collection.New([]int{1, 2, 2, 3, 4, 4, 5})
collection.Dump(c1.Unique(func(a, b int) bool { return a == b }))
// #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// 3 => 4 #int
// 4 => 5 #int
// ]
Example: strings (case-insensitive uniqueness)
c2 := collection.New([]string{"A", "a", "B", "b", "A"})
out2 := c2.Unique(func(a, b string) bool {
return strings.EqualFold(a, b)
})
collection.Dump(out2)
// #[]string [
// 0 => "A" #string
// 1 => "B" #string
// ]
Example: structs (unique by ID)
type User struct {
ID int
Name string
}
c3 := collection.New([]User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
{ID: 1, Name: "Alice Duplicate"},
})
out3 := c3.Unique(func(a, b User) bool {
return a.ID == b.ID
})
collection.Dump(out3)
// #[]main.User [
// 0 => #main.User {
// +ID => 1 #int
// +Name => "Alice" #string
// }
// 1 => #main.User {
// +ID => 2 #int
// +Name => "Bob" #string
// }
// ]
func (Slice[T]) UniqueBy ¶
func (c Slice[T]) UniqueBy[K comparable](keyFn func(T) K) Slice[T]
UniqueBy returns a collection containing the first item for each extracted key. @group Set Operations @behavior immutable @chainable true @terminal false
Example: keep the first word of each length
words := collection.New([]string{"go", "up", "forj", "code"})
unique := words.UniqueBy(func(word string) int {
return len(word)
})
collection.Dump(unique)
// #[]string [
// 0 => "go" #string
// 1 => "forj" #string
// ]
func (Slice[T]) Window ¶
Window returns overlapping (or stepped) windows of the collection. Each window is a slice of length size; iteration advances by step (default 1 if step <= 0). Windows that are shorter than size are omitted. @group Slicing @behavior readonly @chainable false @terminal true
Window allocates the outer result slice. Each window is a capacity-capped view that shares the backing array with the source collection.
Example: integers - step 1
collection.Dump(collection.New([]int{1, 2, 3, 4, 5}).Window(3, 1))
// #[][]int [
// 0 => #[]int [
// 0 => 1 #int
// 1 => 2 #int
// 2 => 3 #int
// ]
// 1 => #[]int [
// 0 => 2 #int
// 1 => 3 #int
// 2 => 4 #int
// ]
// 2 => #[]int [
// 0 => 3 #int
// 1 => 4 #int
// 2 => 5 #int
// ]
// ]
Example: strings - step 2
collection.Dump(collection.New([]string{"a", "b", "c", "d", "e"}).Window(2, 2))
// #[][]string [
// 0 => #[]string [
// 0 => "a" #string
// 1 => "b" #string
// ]
// 1 => #[]string [
// 0 => "c" #string
// 1 => "d" #string
// ]
// ]
Example: structs
type Point struct {
X int
Y int
}
points := collection.New([]Point{
{X: 0, Y: 0},
{X: 1, Y: 1},
{X: 2, Y: 4},
{X: 3, Y: 9},
})
win3 := points.Window(2, 1)
collection.Dump(win3)
// #[][]main.Point [
// 0 => #[]main.Point [
// 0 => #main.Point {
// +X => 0 #int
// +Y => 0 #int
// }
// 1 => #main.Point {
// +X => 1 #int
// +Y => 1 #int
// }
// ]
// 1 => #[]main.Point [
// 0 => #main.Point {
// +X => 1 #int
// +Y => 1 #int
// }
// 1 => #main.Point {
// +X => 2 #int
// +Y => 4 #int
// }
// ]
// 2 => #[]main.Point [
// 0 => #main.Point {
// +X => 2 #int
// +Y => 4 #int
// }
// 1 => #main.Point {
// +X => 3 #int
// +Y => 9 #int
// }
// ]
// ]
func (Slice[T]) Zip ¶
Zip combines this collection with values element-wise into pairs. The resulting length is the smaller of the two inputs. @group Transformation @behavior immutable @chainable false @terminal true
Example: integers and strings
nums := collection.New([]int{1, 2, 3})
words := []string{"one", "two"}
out := nums.Zip(words)
collection.Dump(out)
// #[]collection.Pair[int,string] [
// 0 => #collection.Pair[int,string] {
// +First => 1 #int
// +Second => "one" #string
// }
// 1 => #collection.Pair[int,string] {
// +First => 2 #int
// +Second => "two" #string
// }
// ]
func (Slice[T]) ZipWith ¶
ZipWith combines this collection with a slice using fn up to the shorter length. @group Transformation @behavior immutable @chainable true @terminal false
Example: add corresponding integers
left := collection.New([]int{1, 2, 3})
right := collection.New([]int{10, 20})
sums := left.ZipWith(right, func(a, b int) int {
return a + b
})
collection.Dump(sums)
// #[]int [
// 0 => 11 #int
// 1 => 22 #int
// ]
Source Files
¶
- after.go
- all.go
- any.go
- at.go
- avg.go
- chunk.go
- clone.go
- collection.go
- concat.go
- count_by.go
- difference.go
- doc.go
- dump.go
- each.go
- filter.go
- first.go
- first_where.go
- from_map.go
- generic_methods.go
- index_where.go
- intersect.go
- last.go
- last_where.go
- map.go
- max.go
- median.go
- min.go
- mode.go
- multiply.go
- none.go
- partition.go
- prepend.go
- reduce.go
- retain.go
- reverse.go
- shuffle.go
- skip.go
- skip_last.go
- sort.go
- sum.go
- symmetric_difference.go
- take.go
- take_last.go
- take_until.go
- tap.go
- times.go
- union.go
- unique.go
- unique_comparable.go
- window.go
- zip.go