slicez

package
v1.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 13, 2026 License: MIT Imports: 4 Imported by: 18

README

slicez

Generic slice operations and algorithms for Go

The slicez package provides 70+ utility functions for working with slices. All functions are generic and work with any type.

Quick Reference

By Category:

Installation

go get github.com/modfin/henry/slicez

Usage

import "github.com/modfin/henry/slicez"

numbers := []int{1, 2, 3, 4, 5}
doubled := slicez.Map(numbers, func(n int) int { return n * 2 })
// doubled = []int{2, 4, 6, 8, 10}

Function Categories

Transformation

Transform elements from one form to another.

Map

Transform each element.

// Convert integers to strings
nums := []int{1, 2, 3}
strings := slicez.Map(nums, func(n int) string {
    return fmt.Sprintf("num-%d", n)
})
// strings = []string{"num-1", "num-2", "num-3"}
FlatMap

Map then flatten results.

// Split each string into words
lines := []string{"hello world", "foo bar"}
words := slicez.FlatMap(lines, func(s string) []string {
    return strings.Split(s, " ")
})
// words = []string{"hello", "world", "foo", "bar"}
Reverse

Reverse element order.

nums := []int{1, 2, 3, 4, 5}
reversed := slicez.Reverse(nums)
// reversed = []int{5, 4, 3, 2, 1}
Shuffle

Randomize element order (Fisher-Yates algorithm).

cards := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
shuffled := slicez.Shuffle(cards)
// shuffled = []int{7, 2, 9, 1, 5, 3, 8, 4, 10, 6} (random order)
Filtering

Select or remove elements based on criteria.

Filter

Keep elements matching predicate.

nums := []int{1, 2, 3, 4, 5, 6}
evens := slicez.Filter(nums, func(n int) bool {
    return n%2 == 0
})
// evens = []int{2, 4, 6}
Reject

Remove elements matching predicate (inverse of Filter).

nums := []int{1, 2, 3, 4, 5, 6}
odds := slicez.Reject(nums, func(n int) bool {
    return n%2 == 0
})
// odds = []int{1, 3, 5}
Take

Take first N elements.

nums := []int{1, 2, 3, 4, 5}
first3 := slicez.Take(nums, 3)
// first3 = []int{1, 2, 3}
TakeWhile

Take elements while predicate is true.

nums := []int{1, 2, 3, 4, 5, 1, 2}
ascending := slicez.TakeWhile(nums, func(n int) bool {
    return n < 4
})
// ascending = []int{1, 2, 3}
Drop

Drop first N elements.

nums := []int{1, 2, 3, 4, 5}
rest := slicez.Drop(nums, 2)
// rest = []int{3, 4, 5}
DropWhile

Drop elements while predicate is true.

nums := []int{1, 2, 3, 4, 5}
from4 := slicez.DropWhile(nums, func(n int) bool {
    return n < 4
})
// from4 = []int{4, 5}
Compact

Remove consecutive duplicates.

data := []int{1, 1, 2, 2, 2, 3, 3}
compacted := slicez.Compact(data)
// compacted = []int{1, 2, 3}
Deduplicate

Remove all consecutive duplicates (alias for Compact).

data := []int{1, 1, 2, 1, 2, 2, 3}
result := slicez.Deduplicate(data)
// result = []int{1, 2, 1, 2, 3}
Searching

Find elements and their positions.

Contains

Check if element exists (for comparable types).

nums := []int{1, 2, 3, 4, 5}
has3 := slicez.Contains(nums, 3)     // true
has7 := slicez.Contains(nums, 7)     // false
ContainsBy

Check if element exists using predicate.

users := []User{{Name: "Alice", Age: 30}, {Name: "Bob", Age: 25}}
hasAdult := slicez.ContainsBy(users, func(u User) bool {
    return u.Age >= 18
}) // true
Find

Find first element matching predicate.

nums := []int{1, 2, 3, 4, 5, 6, 7}
firstEven, found := slicez.Find(nums, func(n int) bool {
    return n%2 == 0
})
// firstEven = 2, found = true
FindLast

Find last element matching predicate.

nums := []int{1, 2, 3, 4, 5, 6, 7}
lastEven, found := slicez.FindLast(nums, func(n int) bool {
    return n%2 == 0
})
// lastEven = 6, found = true
Index

Find index of first occurrence (for comparable types).

nums := []int{10, 20, 30, 40, 50}
idx := slicez.Index(nums, 30)   // idx = 2
idx = slicez.Index(nums, 100)   // idx = -1 (not found)
IndexBy

Find index using predicate.

nums := []int{1, 2, 3, 4, 5}
idx := slicez.IndexBy(nums, func(n int) bool {
    return n > 3
}) // idx = 3 (first element > 3)

Binary search on sorted slice.

nums := []int{1, 3, 5, 7, 9, 11, 13}
idx, val := slicez.Search(nums, func(n int) bool {
    return n >= 7
})
// idx = 3, val = 7
Aggregation

Reduce slices to single values or check properties.

Fold / Reduce

Reduce from left to single value.

nums := []int{1, 2, 3, 4, 5}
sum := slicez.Fold(nums, func(acc, val int) int {
    return acc + val
}, 0)
// sum = 15
FoldRight

Reduce from right to single value.

words := []string{"a", "b", "c"}
result := slicez.FoldRight(words, func(acc, val string) string {
    if acc == "" { return val }
    return val + "-" + acc
}, "")
// result = "a-b-c"
Every

Check if all elements equal value (comparable types).

nums := []int{5, 5, 5}
all5 := slicez.Every(nums, 5)   // true
EveryBy

Check if all elements satisfy predicate.

nums := []int{2, 4, 6, 8, 10}
allEven := slicez.EveryBy(nums, func(n int) bool {
    return n%2 == 0
}) // true
Some

Check if any element equals value (alias for Contains).

nums := []int{1, 2, 3, 4, 5}
hasEven := slicez.Some(nums, 2)   // true
SomeBy

Check if any element satisfies predicate.

nums := []int{1, 3, 5, 6, 7}
hasEven := slicez.SomeBy(nums, func(n int) bool {
    return n%2 == 0
}) // true (6 is even)
None

Check if no element equals value.

nums := []int{1, 2, 3}
none0 := slicez.None(nums, 0)   // true
NoneBy

Check if no element satisfies predicate.

nums := []int{1, 2, 3}
noNegatives := slicez.NoneBy(nums, func(n int) bool {
    return n < 0
}) // true
Set Operations

Work with sets (unique collections).

Uniq

Remove all duplicates.

nums := []int{1, 2, 2, 3, 3, 3, 4}
unique := slicez.Uniq(nums)
// unique = []int{1, 2, 3, 4}
UniqBy

Remove duplicates by key function.

type Person struct { Name string; City string }
people := []Person{
    {"Alice", "NYC"}, {"Bob", "LA"}, {"Charlie", "NYC"},
}
// Uniq by city (keeps first occurrence)
byCity := slicez.UniqBy(people, func(p Person) string {
    return p.City
})
// byCity = [{"Alice", "NYC"}, {"Bob", "LA"}]
Union

Combine multiple slices, removing duplicates.

a := []int{1, 2, 3}
b := []int{2, 3, 4}
c := []int{3, 4, 5}
combined := slicez.Union(a, b, c)
// combined = []int{1, 2, 3, 4, 5}
Intersection

Keep only elements present in ALL slices.

a := []int{1, 2, 3, 4}
b := []int{2, 3, 4, 5}
c := []int{3, 4, 5, 6}
common := slicez.Intersection(a, b, c)
// common = []int{3, 4}
Difference

Keep only elements NOT present in all slices.

a := []int{1, 2, 3, 4}
b := []int{2, 3}
diff := slicez.Difference(a, b)
// diff = []int{1, 4}
Complement

Elements in second slice not in first.

seen := []int{1, 2, 3}
all := []int{1, 2, 3, 4, 5, 6}
newOnes := slicez.Complement(seen, all)
// newOnes = []int{4, 5, 6}
XOR

Symmetric difference (elements in exactly one slice).

a := []int{1, 2, 3}
b := []int{2, 3, 4}
xor := slicez.XOR(a, b)
// xor = []int{1, 4}
Sorting

Sort and find extrema.

Sort

Sort using natural order.

nums := []int{3, 1, 4, 1, 5, 9, 2, 6}
sorted := slicez.Sort(nums)
// sorted = []int{1, 1, 2, 3, 4, 5, 6, 9}
SortBy

Sort using custom comparison.

type Person struct { Name string; Age int }
people := []Person{
    {"Alice", 30}, {"Bob", 25}, {"Charlie", 35},
}
byAge := slicez.SortBy(people, func(a, b Person) bool {
    return a.Age < b.Age
})
// byAge = [{Bob 25} {Alice 30} {Charlie 35}]
OrderBy

Sort by extracted key with optional order direction.

// Sort strings by length (ascending default)
words := []string{"banana", "pie", "apple", "kiwi"}
sorted := slicez.OrderBy(words, func(s string) int { return len(s) })
// sorted = []string{"pie", "kiwi", "apple", "banana"}

// Sort by length descending
sortedDesc := slicez.OrderBy(words, func(s string) int { return len(s) }, compare.Desc[int])
// sortedDesc = []string{"banana", "apple", "kiwi", "pie"}

// Sort people by age
type Person struct { Name string; Age int }
people := []Person{{"Alice", 30}, {"Bob", 25}, {"Charlie", 35}}
byAge := slicez.OrderBy(people, func(p Person) int { return p.Age })
// byAge = [{Bob 25} {Alice 30} {Charlie 35}]
IsSorted

Check if slice is sorted.

nums := []int{1, 2, 3, 4, 5}
slicez.IsSorted(nums)   // true
Max

Find maximum value.

max := slicez.Max(3, 1, 4, 1, 5, 9, 2, 6)
// max = 9
Min

Find minimum value.

min := slicez.Min(3, 1, 4, 1, 5, 9, 2, 6)
// min = 1
Grouping

Organize elements into groups.

GroupBy

Group by key function.

type Person struct { Name string; Age int }
people := []Person{
    {"Alice", 30}, {"Bob", 25}, {"Charlie", 30},
}
byAge := slicez.GroupBy(people, func(p Person) int {
    return p.Age
})
// byAge = map[int][]Person{
//     30: {{"Alice", 30}, {"Charlie", 30}},
//     25: {{"Bob", 25}},
// }
Partition

Split into two groups by predicate.

nums := []int{1, 2, 3, 4, 5, 6}
evens, odds := slicez.Partition(nums, func(n int) bool {
    return n%2 == 0
})
// evens = []int{2, 4, 6}
// odds = []int{1, 3, 5}
Chunk

Split into chunks of size N.

nums := []int{1, 2, 3, 4, 5, 6, 7}
chunks := slicez.Chunk(nums, 3)
// chunks = [][]int{{1, 2, 3}, {4, 5, 6}, {7}}
ChunkBy

Group consecutive elements satisfying predicate.

nums := []int{1, 2, 3, 2, 2, 1}
groups := slicez.ChunkBy(nums, func(a, b int) bool {
    return a <= b  // Group while ascending
})
// groups = [][]int{{1, 2, 3}, {2, 2}, {1}}
Combining

Combine multiple slices.

Concat

Concatenate slices.

a := []int{1, 2, 3}
b := []int{4, 5, 6}
c := []int{7, 8, 9}
combined := slicez.Concat(a, b, c)
// combined = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
Zip

Combine two slices element-wise.

nums := []int{1, 2, 3}
strs := []string{"a", "b", "c"}
zipped := slicez.Zip(nums, strs, func(n int, s string) string {
    return fmt.Sprintf("%d:%s", n, s)
})
// zipped = []string{"1:a", "2:b", "3:c"}
Zip2

Combine three slices.

a := []int{1, 2, 3}
b := []int{10, 20, 30}
c := []string{"x", "y", "z"}
result := slicez.Zip2(a, b, c, func(x, y int, z string) string {
    return fmt.Sprintf("%d-%d-%s", x, y, z)
})
// result = []string{"1-10-x", "2-20-y", "3-30-z"}
Unzip

Split slice of pairs into two slices.

pairs := []Pair{{1, 10}, {2, 20}, {3, 30}}
as, bs := slicez.Unzip(pairs, func(p Pair) (int, int) {
    return p.A, p.B
})
// as = []int{1, 2, 3}
// bs = []int{10, 20, 30}
Interleave

Interleave multiple slices round-robin.

a := []int{1, 4, 7}
b := []int{2, 5, 8}
c := []int{3, 6, 9}
interleaved := slicez.Interleave(a, b, c)
// interleaved = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
Utilities
Clone

Create a copy of a slice.

original := []int{1, 2, 3}
copy := slicez.Clone(original)
// copy = []int{1, 2, 3}
Sample

Get N random elements.

nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sample := slicez.Sample(nums, 3)
// sample = []int{7, 2, 9} (3 random elements)
Fill

Create slice filled with value.

fives := slicez.Fill(5, 5)
// fives = []int{5, 5, 5, 5, 5}
Range

Create range of integers.

nums := slicez.Range(1, 5)
// nums = []int{1, 2, 3, 4, 5}
RangeStep

Create range with step.

evens := slicez.RangeStep(0, 10, 2)
// evens = []int{0, 2, 4, 6, 8, 10}
Repeat

Repeat slice N times.

pattern := []int{1, 2}
repeated := slicez.Repeat(pattern, 3)
// repeated = []int{1, 2, 1, 2, 1, 2}
Head / Tail / Initial / Last

Access slice ends.

nums := []int{1, 2, 3, 4, 5}

head, _ := slicez.Head(nums)      // head = 1
tail := slicez.Tail(nums)         // tail = []int{2, 3, 4, 5}
initial := slicez.Initial(nums)   // initial = []int{1, 2, 3, 4}
last, _ := slicez.Last(nums)      // last = 5
Nth

Get element at index (wraps around).

nums := []int{10, 20, 30, 40, 50}
slicez.Nth(nums, 0)   // 10 (first)
slicez.Nth(nums, 2)   // 30
slicez.Nth(nums, -1)  // 50 (last)
slicez.Nth(nums, 5)   // 10 (wraps around)
KeyBy

Create map from slice.

users := []User{{1, "Alice"}, {2, "Bob"}}
byID := slicez.KeyBy(users, func(u User) int {
    return u.ID
})
// byID = map[int]User{1: {1, "Alice"}, 2: {2, "Bob"}}
Associate

Convert slice to map (key-value pairs).

nums := []int{1, 2, 3, 4, 5}
squares := slicez.Associate(nums, func(n int) (int, int) {
    return n, n * n
})
// squares = map[int]int{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
SliceToMap

Alias for Associate.

// Same as Associate
result := slicez.SliceToMap(nums, mapper)
Flatten

Flatten 2D slice to 1D.

flat := slicez.Flatten(nested)
// flat = []int{1, 2, 3, 4, 5, 6}
Join

Join 2D slice with separator.

joined := slicez.Join(nested, []string{"-"})
// joined = []string{"a", "b", "-", "c", "d"}
Intersperse

Insert element between elements.

nums := []int{1, 2, 3}
withCommas := slicez.Intersperse(nums, 0)
// withCommas = []int{1, 0, 2, 0, 3}
Transpose

Transpose matrix (rows become columns).

matrix := [][]int{
    {1, 2, 3},
    {4, 5, 6},
}
transposed := slicez.Transpose(matrix)
// transposed = [][]int{
//     {1, 4},
//     {2, 5},
//     {3, 6},
// }
SlidingWindow

Create sliding windows.

nums := []int{1, 2, 3, 4, 5}
windows := slicez.SlidingWindow(nums, 3)
// windows = [][]int{
//     {1, 2, 3},
//     {2, 3, 4},
//     {3, 4, 5},
// }
SplitAt

Split at index.

nums := []int{1, 2, 3, 4, 5}
left, right := slicez.SplitAt(nums, 2)
// left = []int{1, 2}
// right = []int{3, 4, 5}
Span

Split where predicate becomes false.

nums := []int{1, 2, 3, 4, 5}
init, rest := slicez.Span(nums, func(n int) bool {
    return n < 4
})
// init = []int{1, 2, 3}
// rest = []int{4, 5}
ScanLeft / ScanRight

Running totals.

nums := []int{1, 2, 3, 4}
running := slicez.ScanLeft(nums, func(acc, n int) int {
    return acc + n
}, 0)
// running = []int{0, 1, 3, 6, 10}
IsAllUnique

Check if all elements are unique.

slicez.IsAllUnique([]int{1, 2, 3})    // true
slicez.IsAllUnique([]int{1, 2, 2})    // false
ForEach / ForEachRight

Apply function to each element.

slicez.ForEach([]int{1, 2, 3}, func(n int) {
    fmt.Println(n)
})
// Prints 1, 2, 3
Cut

Split at first occurrence.

nums := []int{1, 2, 3, 4, 5}
left, right, found := slicez.Cut(nums, 3)
// left = []int{1, 2}
// right = []int{4, 5}
// found = true
Replace

Replace elements.

nums := []int{1, 2, 3, 2, 4}
replaced := slicez.Replace(nums, 2, 9, 1) // Replace 1 occurrence of 2 with 9
// replaced = []int{1, 9, 3, 2, 4}
Without

Remove specific values.

nums := []int{1, 2, 3, 2, 4, 2}
result := slicez.Without(nums, 2)
// result = []int{1, 3, 4}

Performance Notes

  • Pre-allocation: Functions like Map, Filter, Union pre-allocate result slices
  • Efficient sampling: Sample uses Fisher-Yates or swap-to-end algorithms
  • In-place mutations: Some functions (marked in docs) modify input for performance
  • Zero-allocation: Type aliases (Pipe, Set) have no overhead

See Also

  • pipez - Method-chaining API for slice operations
  • compare - Comparison utilities and constraints

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Associate

func Associate[E any, K comparable, V any](slice []E, mapper func(e E) (key K, value V)) map[K]V

Associate converts a slice to a map using a mapper function. Each element is transformed into a key-value pair. Later elements overwrite earlier ones if keys collide. Pre-allocates map capacity for efficiency.

Example:

// Index strings by length
slicez.Associate([]string{"hi", "hello", "hey"}, func(s string) (int, string) {
    return len(s), s
})
// Returns map[int]string{2: "hi", 3: "hey", 5: "hello"}

func Chunk

func Chunk[A any](slice []A, n int) [][]A

Chunk splits a slice into chunks of size n. Each chunk (except possibly the last) has exactly n elements. The last chunk may have fewer than n elements if the slice length isn't divisible by n.

Example:

slicez.Chunk([]int{1, 2, 3, 4, 5, 6, 7}, 3)
// Returns [][]int{{1, 2, 3}, {4, 5, 6}, {7}}

slicez.Chunk([]string{"a", "b", "c", "d", "e"}, 2)
// Returns [][]string{{"a", "b"}, {"c", "d"}, {"e"}}

slicez.Chunk([]int{1, 2, 3}, 5)
// Returns [][]int{{1, 2, 3}} (single chunk, smaller than n)

func ChunkBy added in v1.2.0

func ChunkBy[A any](slice []A, predicate func(a, b A) bool) [][]A

ChunkBy groups consecutive elements that satisfy the predicate. The predicate receives consecutive elements (a, b) and should return true if they should be grouped together.

Example:

ChunkBy([]int{1, 1, 1, 2, 2, 3, 3, 3}, func(a, b int) bool { return a == b })
// Returns [][]int{{1, 1, 1}, {2, 2}, {3, 3, 3}}

ChunkBy([]int{1, 2, 3, 2, 2, 1}, func(a, b int) bool { return a <= b })
// Returns [][]int{{1, 2, 3}, {2, 2}, {1}}

func Clone

func Clone[E any](s []E) []E

Clone creates a copy of the slice. Returns nil if the input slice is nil (preserves nil vs empty distinction). The returned slice has the same elements but different backing array.

Example:

original := []int{1, 2, 3}
copy := slicez.Clone(original)
copy[0] = 99
// original is still []int{1, 2, 3}
// copy is []int{99, 2, 3}

// Nil preservation
var nilSlice []int
result := slicez.Clone(nilSlice)  // result is nil, not []int{}

func Compact

func Compact[A comparable](slice []A) []A

Compact removes consecutive duplicate elements from a slice. Only removes duplicates that are adjacent; non-consecutive duplicates are kept. Uses equality comparison (==) for comparable types.

Example:

slicez.Compact([]int{1, 1, 2, 1, 2, 2, 2})
// Returns []int{1, 2, 1, 2}

slicez.Compact([]string{"a", "a", "b", "b", "a"})
// Returns []string{"a", "b", "a"}

// Removing duplicate spaces
slicez.Compact([]rune("hello    world"))
// Returns []rune{'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}

func CompactBy

func CompactBy[A any](slice []A, equal func(a, b A) bool) []A

CompactBy removes consecutive duplicate elements using a custom equality function. Only adjacent elements are compared; non-consecutive duplicates are kept.

Example:

// Compact consecutive runs of strings with equal length
slicez.CompactBy([]string{"a", "to", "go", "bee", "at"}, func(a, b string) bool {
    return len(a) == len(b)
})
// Returns []string{"a", "to", "bee", "at"}

func Compare

func Compare[E compare.Ordered](s1, s2 []E) int

Compare performs lexicographic comparison of two slices. Returns -1 if s1 < s2, 0 if s1 == s2, and +1 if s1 > s2. Comparison is done element by element using natural ordering. If all elements are equal, the shorter slice is considered less.

Example:

slicez.Compare([]int{1, 2, 3}, []int{1, 2, 4})  // returns -1
slicez.Compare([]int{1, 2, 3}, []int{1, 2, 3})  // returns 0
slicez.Compare([]int{1, 2, 3}, []int{1, 2})      // returns +1 (longer)
slicez.Compare([]string{"a", "b"}, []string{"a", "c"}) // returns -1

func CompareBy

func CompareBy[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int

CompareBy performs lexicographic comparison of two slices using a custom comparison function. Returns -1 if s1 < s2, 0 if s1 == s2, and +1 if s1 > s2. The comparison function should return negative if a < b, zero if a == b, positive if a > b.

Example:

// Compare by length
slicez.CompareBy([]string{"a", "bb"}, []string{"ccc", "d"}, func(a, b string) int {
    return len(a) - len(b)
}) // returns -1 (first string shorter overall)

// Compare different types
slicez.CompareBy([]int{1, 2}, []float64{1.0, 2.0, 3.0}, func(i int, f float64) int {
    if float64(i) < f { return -1 }
    if float64(i) > f { return +1 }
    return 0
}) // returns -1 (second slice longer)

func Complement

func Complement[A comparable](a, b []A) []A

Complement returns elements in b that are not in a (set difference b - a). Returns a copy of b with all elements from a removed. Useful for filtering: keep only elements from b not seen in a.

Example:

allowed := []int{1, 2, 3}
all := []int{1, 2, 3, 4, 5, 6}
slicez.Complement(allowed, all)
// Returns []int{4, 5, 6} (elements in all but not in allowed)

// Filter out seen items
seen := []string{"a", "b"}
newItems := []string{"b", "c", "d", "a"}
slicez.Complement(seen, newItems)
// Returns []string{"c", "d"}

func ComplementBy

func ComplementBy[A any, B comparable](by func(a A) B, a, b []A) []A

ComplementBy returns elements in b not in a using a key function. Elements are compared by their keys rather than direct equality.

Example:

type User struct { ID int; Name string }
existing := []User{{1, "Alice"}, {2, "Bob"}}
newUsers := []User{{2, "Robert"}, {3, "Charlie"}, {4, "Dave"}}
slicez.ComplementBy(func(u User) int { return u.ID }, existing, newUsers)
// Returns [{3, "Charlie"}, {4, "Dave"}] (ID 2 already exists)

func Concat

func Concat[A any](slices ...[]A) []A

Concat concatenates multiple slices in order into a single new slice. Returns an empty slice if no slices are provided. Preserves order: elements from first slice appear first, then second, etc.

Example:

slicez.Concat([]int{1, 2}, []int{3, 4}, []int{5, 6})
// Returns []int{1, 2, 3, 4, 5, 6}

slicez.Concat([]string{"a"}, []string{"b", "c"})
// Returns []string{"a", "b", "c"}

slicez.Concat[int]() // Returns []int{} (empty)

func Contains

func Contains[E comparable](s []E, needle E) bool

Contains checks if needle exists in slice. Uses == comparison for equality. Returns false if slice is empty.

Example:

slicez.Contains([]int{1, 2, 3}, 2)          // returns true
slicez.Contains([]string{"a", "b"}, "c")     // returns false
slicez.Contains([]int{}, 1)                  // returns false

func ContainsBy

func ContainsBy[E any](s []E, f func(e E) bool) bool

ContainsBy checks if any element satisfies the predicate function. Returns false if slice is empty or no element satisfies the condition.

Example:

// Check if any number is even
slicez.ContainsBy([]int{1, 3, 5, 6, 7}, func(n int) bool {
    return n%2 == 0
}) // returns true

// Check if any string is longer than 5 chars
slicez.ContainsBy([]string{"a", "bb", "ccc"}, func(s string) bool {
    return len(s) > 5
}) // returns false

func Cut

func Cut[E comparable](s []E, needle E) (left, right []E, found bool)

Cut splits the slice at the first occurrence of needle. It returns left (elements before needle), right (elements after needle), and a boolean indicating if the needle was found. The needle itself is not included in either part.

Example:

left, right, found := slicez.Cut([]int{1, 2, 3, 4, 5}, 3)
// left = []int{1, 2}, right = []int{4, 5}, found = true

left, right, found := slicez.Cut([]string{"a", "b", "c"}, "d")
// left = []string{"a", "b", "c"}, right = nil, found = false

func CutBy

func CutBy[E any](s []E, on func(E) bool) (left, right []E, found bool)

CutBy splits the slice at the first element where on returns true. It returns left (elements before the match), right (elements after the match), and a boolean indicating if a match was found. The matching element is not included in either part.

Example:

// Cut at first number > 5
left, right, found := slicez.CutBy([]int{1, 2, 6, 7, 8}, func(n int) bool {
    return n > 5
})
// left = []int{1, 2}, right = []int{7, 8}, found = true

// Cut at first string starting with "c"
left, right, found := slicez.CutBy([]string{"apple", "banana", "cherry"}, func(s string) bool {
    return strings.HasPrefix(s, "c")
})
// left = []string{"apple", "banana"}, right = []string{}, found = true

func Deduplicate added in v1.2.0

func Deduplicate[A comparable](slice []A) []A

Deduplicate removes consecutive duplicate elements from a slice. Unlike Uniq which removes all duplicates, this only removes consecutive duplicates.

Example:

Deduplicate([]int{1, 1, 2, 2, 2, 3, 3}) // Returns []int{1, 2, 3}
Deduplicate([]int{1, 2, 1, 2, 1})      // Returns []int{1, 2, 1, 2, 1}

func Difference

func Difference[A comparable](slices ...[]A) []A

Difference returns unique elements from all slices, excluding keys present in every slice. For two slices, this is the classic symmetric difference. For more than two slices, elements are excluded only when they appear in all inputs. Output order follows first appearance across inputs.

Example:

slicez.Difference([]int{1, 2, 3}, []int{2, 3, 4})
// Returns []int{1, 4} (2 and 3 are in both, so removed)

// Three slices: only values present in all three are excluded
slicez.Difference([]int{1, 2}, []int{2, 3}, []int{3, 4})
// Returns []int{1, 2, 3, 4} (no value appears in all three)

func DifferenceBy

func DifferenceBy[A any, B comparable](by func(a A) B, slices ...[]A) []A

DifferenceBy is Difference with custom key extraction. Keys present in every input slice are excluded; remaining keys are kept once.

Example:

type Person struct { Name string; Age int }
a := []Person{{"Alice", 30}, {"Bob", 25}}
b := []Person{{"Charlie", 30}, {"Dave", 35}}
slicez.DifferenceBy(func(p Person) int { return p.Age }, a, b)
// Returns [{Bob 25} {Dave 35}] (age 30 appears in both, so excluded)

func Drop

func Drop[A any](slice []A, i int) []A

Drop returns a slice with the first i elements removed. If i <= 0, returns a copy of the entire slice. If i >= len(slice), returns nil.

Example:

slicez.Drop([]int{1, 2, 3, 4, 5}, 3)
// Returns []int{4, 5}

slicez.Drop([]string{"a", "b", "c", "d"}, 2)
// Returns []string{"c", "d"}

slicez.Drop([]int{1, 2, 3}, 10) // Returns nil

slicez.Drop([]int{1, 2, 3}, 0)  // Returns []int{1, 2, 3} (copy)

func DropRight

func DropRight[A any](slice []A, i int) []A

DropRight returns a slice with the last i elements removed. If i <= 0, returns a copy of the entire slice. If i >= len(slice), returns nil.

Example:

slicez.DropRight([]int{1, 2, 3, 4, 5}, 3)
// Returns []int{1, 2}

slicez.DropRight([]string{"a", "b", "c", "d"}, 2)
// Returns []string{"a", "b"}

slicez.DropRight([]int{1, 2, 3}, 10) // Returns nil

slicez.DropRight([]int{1, 2, 3}, 0)  // Returns []int{1, 2, 3} (copy)

func DropRightWhile

func DropRightWhile[A any](slice []A, drop func(a A) bool) []A

DropRightWhile drops elements from the end while the predicate returns true. Returns a new slice ending at the last element where the predicate returns false. Returns nil if all elements are dropped or if the slice is empty.

Example:

// Drop from right while greater than 5
slicez.DropRightWhile([]int{1, 2, 6, 7, 8}, func(n int) bool {
    return n > 5
})
// Returns []int{1, 2}

// Drop trailing zeros
slicez.DropRightWhile([]int{1, 2, 3, 0, 0, 0}, func(n int) bool {
    return n == 0
})
// Returns []int{1, 2, 3}

// When no elements match from right
slicez.DropRightWhile([]int{1, 2, 3}, func(n int) bool { return n > 10 })
// Returns []int{1, 2, 3} (unchanged copy)

func DropWhile

func DropWhile[A any](slice []A, drop func(a A) bool) []A

DropWhile drops elements from the start while the predicate returns true. Returns a new slice starting from the first element where the predicate returns false. Returns nil if all elements are dropped or if the slice is empty.

Example:

// Drop while less than 3
slicez.DropWhile([]int{1, 2, 3, 4, 5}, func(n int) bool {
    return n < 3
})
// Returns []int{3, 4, 5}

// Drop strings starting with "a"
slicez.DropWhile([]string{"apple", "apricot", "banana", "cherry"}, func(s string) bool {
    return strings.HasPrefix(s, "a")
})
// Returns []string{"banana", "cherry"}

// When no elements match
slicez.DropWhile([]int{1, 2, 3}, func(n int) bool { return n > 10 })
// Returns []int{1, 2, 3} (unchanged copy)

func Equal

func Equal[A comparable](s1, s2 []A) bool

Equal checks if two slices are equal. Two slices are considered equal if they have the same length and each element at the same index is equal (== comparison).

Example:

slicez.Equal([]int{1, 2, 3}, []int{1, 2, 3})        // returns true
slicez.Equal([]int{1, 2, 3}, []int{1, 2, 3, 4})    // returns false (different lengths)
slicez.Equal([]string{"a", "b"}, []string{"a", "b"}) // returns true
slicez.Equal([]int{1, 2}, []int{2, 1})             // returns false (different order)

func EqualBy

func EqualBy[E1, E2 any](s1 []E1, s2 []E2, eq func(E1, E2) bool) bool

EqualBy checks if two slices are equal using a custom equality function. It returns true if both slices have the same length and the equality function returns true for every pair of elements at the same index.

This is useful when comparing slices of different types, or when you need custom comparison logic (e.g., case-insensitive string comparison).

Example:

// Compare strings ignoring case
s1 := []string{"hello", "world"}
s2 := []string{"HELLO", "WORLD"}
slicez.EqualBy(s1, s2, func(a, b string) bool {
    return strings.EqualFold(a, b)
}) // returns true

// Compare different types
ints := []int{1, 2, 3}
floats := []float64{1.0, 2.0, 3.0}
slicez.EqualBy(ints, floats, func(i int, f float64) bool {
    return float64(i) == f
}) // returns true

func Every

func Every[A comparable](slice []A, needle A) bool

Every checks if all elements equal the given value. Returns true if the slice is empty (vacuous truth). Uses equality comparison (==).

Example:

slicez.Every([]int{5, 5, 5}, 5)   // Returns true
slicez.Every([]int{5, 5, 6}, 5)   // Returns false
slicez.Every([]string{"a", "a"}, "a") // Returns true
slicez.Every([]int{}, 5)         // Returns true (empty slice)

func EveryBy

func EveryBy[A any](slice []A, predicate func(A) bool) bool

EveryBy checks if the predicate returns true for all elements. Returns true if the slice is empty (vacuous truth). Useful for validation and type checking.

Example:

// Check if all numbers are positive
slicez.EveryBy([]int{1, 2, 3, 4}, func(n int) bool {
    return n > 0
}) // Returns true

// Check if all strings are non-empty
slicez.EveryBy([]string{"a", "b", ""}, func(s string) bool {
    return len(s) > 0
}) // Returns false (empty string at end)

slicez.EveryBy([]int{}, func(n int) bool { return n > 0 })
// Returns true (empty slice)

func Fill added in v1.2.0

func Fill[A any](n int, value A) []A

Fill creates a slice of length n filled with the given value.

Example:

Fill(5, 42)    // Returns []int{42, 42, 42, 42, 42}
Fill(3, "x")   // Returns []string{"x", "x", "x"}

func Filter

func Filter[A any](slice []A, include func(a A) bool) []A

Filter returns a new slice containing only elements where the predicate returns true. Returns a new slice; the original is not modified. Preserves order of elements.

Example:

// Keep only even numbers
slicez.Filter([]int{1, 2, 3, 4, 5, 6}, func(n int) bool {
    return n%2 == 0
})
// Returns []int{2, 4, 6}

// Keep strings longer than 3 chars
slicez.Filter([]string{"a", "bb", "ccc", "dddd"}, func(s string) bool {
    return len(s) > 3
})
// Returns []string{"dddd"}

// Filter with index (using FilterIdx)
slicez.FilterIdx([]int{10, 20, 30, 40}, func(i, n int) bool {
    return i%2 == 0 && n > 15
})
// Returns []int{30} (index 2, value > 15)

func FilterIdx added in v1.2.0

func FilterIdx[A any](slice []A, include func(index int, a A) bool) []A

FilterIdx filters elements with index awareness. The predicate receives both the index and the element.

Example:

FilterIdx([]int{10, 20, 30, 40}, func(i int, n int) bool {
    return i%2 == 0 && n > 15
})
// Returns []int{30} (index 2 is even and value > 15)

func Find

func Find[E any](s []E, equal func(E) bool) (e E, found bool)

Find returns the first element that satisfies the predicate function. Returns the element and true if found, or the zero value and false if not found.

Example:

// Find first number > 10
val, found := slicez.Find([]int{1, 5, 12, 7, 15}, func(n int) bool {
    return n > 10
})
// val = 12, found = true

// Find first string containing "e"
val, found := slicez.Find([]string{"cat", "dog", "elephant"}, func(s string) bool {
    return strings.Contains(s, "e")
})
// val = "elephant", found = true

func FindLast

func FindLast[E any](s []E, equal func(E) bool) (e E, found bool)

FindLast returns the last element that satisfies the predicate function. Returns the element and true if found, or the zero value and false if not found.

Example:

// Find last even number
val, found := slicez.FindLast([]int{1, 2, 3, 4, 5}, func(n int) bool {
    return n%2 == 0
})
// val = 4, found = true

// Find last string starting with "a"
val, found := slicez.FindLast([]string{"apple", "banana", "apricot", "cherry"}, func(s string) bool {
    return strings.HasPrefix(s, "a")
})
// val = "apricot", found = true

func FlatMap

func FlatMap[A any, B any](slice []A, f func(a A) []B) []B

FlatMap maps each element to a slice and flattens the results. Combines Map and Flatten operations. Useful for "expanding" elements.

Example:

// Expand each number to [n, n*2]
slicez.FlatMap([]int{1, 2, 3}, func(n int) []int {
    return []int{n, n * 2}
})
// Returns []int{1, 2, 2, 4, 3, 6}

// Split strings into words
slicez.FlatMap([]string{"hello world", "foo bar"}, func(s string) []string {
    return strings.Split(s, " ")
})
// Returns []string{"hello", "world", "foo", "bar"}

func Flatten

func Flatten[A any](slice [][]A) []A

Flatten flattens a 2D slice into a 1D slice. Concatenates all sub-slices in order. Pre-allocates capacity for efficiency. Returns empty slice for nil or empty input.

Example:

slicez.Flatten([][]int{{1, 2}, {3, 4}, {5, 6}})
// Returns []int{1, 2, 3, 4, 5, 6}

slicez.Flatten([][]string{{"a", "b"}, {"c"}, {}, {"d", "e"}})
// Returns []string{"a", "b", "c", "d", "e"}

slicez.Flatten([][]int{})
// Returns []int{}

func Fold

func Fold[I any, A any](slice []I, combined func(accumulator A, val I) A, init A) A

Fold reduces a slice from left to right, accumulating a result. Applies the combine function to each element with the current accumulator. Also known as Reduce or Inject in other languages.

Example:

// Sum all numbers
slicez.Fold([]int{1, 2, 3, 4}, func(acc, val int) int {
    return acc + val
}, 0)
// Returns 10

// Concatenate strings with separator
slicez.Fold([]string{"a", "b", "c"}, func(acc, val string) string {
    if acc == "" {
        return val
    }
    return acc + "-" + val
}, "")
// Returns "a-b-c"

func FoldRight

func FoldRight[I any, A any](slice []I, combined func(accumulator A, val I) A, init A) A

FoldRight reduces a slice from right to left, accumulating a result. Like Fold but processes elements from the end to the beginning.

Example:

// Build string from right (reverses order)
slicez.FoldRight([]string{"a", "b", "c"}, func(acc, val string) string {
    if acc == "" {
        return val
    }
    return val + "-" + acc
}, "")
// Returns "a-b-c" (different associativity than Fold)

// For subtraction: FoldRight([1,2,3], -, 0) = 1-(2-(3-0)) = 2
// While Fold([1,2,3], -, 0) = ((0-1)-2)-3 = -6

func ForEach

func ForEach[A any](slice []A, apply func(a A))

ForEach applies a function to each element of the slice from left to right. The function is called purely for side effects; it returns nothing. Similar to a for-range loop but as a higher-order function.

Example:

// Print each element
slicez.ForEach([]int{1, 2, 3}, func(n int) {
    fmt.Println(n)
})
// Output: 1 2 3 (on separate lines)

// Accumulate sum
sum := 0
slicez.ForEach([]int{1, 2, 3, 4}, func(n int) {
    sum += n
})
// sum = 10

func ForEachRight

func ForEachRight[A any](slice []A, apply func(a A))

ForEachRight applies a function to each element from right to left. The function is called purely for side effects; it returns nothing. Processes elements in reverse order compared to ForEach.

Example:

// Print in reverse order
slicez.ForEachRight([]int{1, 2, 3}, func(n int) {
    fmt.Println(n)
})
// Output: 3 2 1 (on separate lines)

// Build reversed string
var result string
slicez.ForEachRight([]string{"a", "b", "c"}, func(s string) {
    result += s
})
// result = "cba"

func GroupBy

func GroupBy[A any, B comparable](slice []A, key func(a A) B) map[B][]A

GroupBy groups slice elements by a key function into a map. Returns a map where each key maps to a slice of all elements with that key. For ordered iteration, use GroupByOrdered instead.

Example:

// Group integers by even/odd
slicez.GroupBy([]int{1, 2, 3, 4, 5}, func(n int) string {
    if n%2 == 0 {
        return "even"
    }
    return "odd"
})
// Returns map[string][]int{"odd": {1, 3, 5}, "even": {2, 4}}

// Group strings by first letter
slicez.GroupBy([]string{"apple", "avocado", "banana"}, func(s string) string {
    return string(s[0])
})
// Returns map[string][]string{"a": {"apple", "avocado"}, "b": {"banana"}}
func Head[A any](slice []A) (A, error)

Head returns the first element of the slice. Returns an error if the slice is empty or nil.

Example:

val, err := slicez.Head([]int{1, 2, 3})
// val = 1, err = nil

val, err := slicez.Head([]string{"a", "b"})
// val = "a", err = nil

val, err := slicez.Head([]int{})
// val = 0 (zero value), err = "slice does not have any elements"

func Index

func Index[E comparable](s []E, needle E) int

Index returns the index of the first occurrence of needle in s. It returns -1 if needle is not found. Uses == comparison for equality.

Example:

slicez.Index([]int{1, 2, 3, 2, 1}, 2)        // returns 1 (first occurrence)
slicez.Index([]string{"a", "b", "c"}, "b")    // returns 1
slicez.Index([]int{1, 2, 3}, 4)             // returns -1 (not found)

func IndexBy

func IndexBy[E any](s []E, f func(E) bool) int

IndexBy returns the index of the first element where f returns true. It returns -1 if no element satisfies the condition.

Example:

// Find first even number
slicez.IndexBy([]int{1, 3, 5, 6, 7}, func(n int) bool {
    return n%2 == 0
}) // returns 3

// Find first string longer than 3 characters
slicez.IndexBy([]string{"a", "bb", "ccc", "dddd"}, func(s string) bool {
    return len(s) > 3
}) // returns 3

func Initial

func Initial[A any](slice []A) []A

Initial returns a new slice containing all elements except the last. Returns nil if the slice has 0 or 1 elements. Complement of Tail - gets all but the last element.

Example:

slicez.Initial([]int{1, 2, 3, 4})
// Returns []int{1, 2, 3}

slicez.Initial([]string{"a", "b", "c"})
// Returns []string{"a", "b"}

slicez.Initial([]int{1}) // Returns nil

func Interleave

func Interleave[A any](slices ...[]A) []A

Interleave interleaves multiple slices round-robin style. Takes first element from each slice, then second element from each, etc. If slices have different lengths, shorter slices are skipped once exhausted. Useful for zipping/combining multiple data streams.

Example:

// Round-robin interleave
slicez.Interleave([]int{1, 5, 9}, []int{2, 6, 10}, []int{3, 7, 11}, []int{4, 8, 12})
// Returns []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}

// Different lengths (shorter slices skipped when exhausted)
slicez.Interleave([]int{1}, []int{2, 5, 8}, []int{3, 6}, []int{4, 7, 9, 10})
// Returns []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

// Two slices (like a simple zip)
slicez.Interleave([]int{1, 2, 3}, []int{10, 20, 30})
// Returns []int{1, 10, 2, 20, 3, 30}

func Intersection

func Intersection[A comparable](slices ...[]A) []A

Intersection returns the set intersection of multiple slices. Returns elements that appear in ALL slices. Preserves order from first slice.

Example:

slicez.Intersection([]int{1, 2, 3}, []int{2, 3, 4}, []int{3, 4, 5})
// Returns []int{3} (only element in all three)

slicez.Intersection([]string{"a", "b", "c"}, []string{"b", "c", "d"})
// Returns []string{"b", "c"}

func IntersectionBy

func IntersectionBy[A any, B comparable](by func(a A) B, slices ...[]A) []A

IntersectionBy returns the intersection using a key function. Returns elements whose keys appear in ALL slices. Preserves order from first slice.

Example:

type Person struct { Name string; Age int }
a := []Person{{"Alice", 30}, {"Bob", 25}}
b := []Person{{"Charlie", 30}, {"Dave", 25}}
slicez.IntersectionBy(func(p Person) int { return p.Age }, a, b)
// Returns [{Alice 30} {Bob 25}] (ages 30 and 25 in both)

func Intersperse added in v1.2.0

func Intersperse[A any](slice []A, element A) []A

Intersperse inserts element between each element of the slice. Returns a new slice with the element inserted between consecutive elements.

Example:

Intersperse([]int{1, 2, 3}, 0)
// Returns []int{1, 0, 2, 0, 3}

func IsAllUnique added in v1.2.0

func IsAllUnique[A comparable](slice []A) bool

IsAllUnique returns true if all elements in the slice are unique (no duplicates). Uses a map for O(n) time complexity.

Example:

IsAllUnique([]int{1, 2, 3})    // Returns true
IsAllUnique([]int{1, 2, 2, 3}) // Returns false

func IsSorted added in v1.2.0

func IsSorted[A compare.Ordered](slice []A) bool

IsSorted returns true if the slice is sorted in ascending order. Uses the natural ordering of the elements.

Example:

IsSorted([]int{1, 2, 3})    // Returns true
IsSorted([]int{3, 2, 1})    // Returns false
IsSorted([]int{1, 2, 2, 3}) // Returns true (allows duplicates)

func IsSortedBy added in v1.2.0

func IsSortedBy[A any](slice []A, less func(a, b A) bool) bool

IsSortedBy returns true if the slice is sorted according to the provided comparison function. The less function should return true if a should come before b.

Example:

IsSortedBy([]string{"a", "bb", "ccc"}, func(a, b string) bool {
    return len(a) < len(b)
}) // Returns true (sorted by length)

func Join

func Join[E any](slices [][]E, glue []E) []E

Join concatenates multiple slices with glue inserted between each pair. Similar to strings.Join but works with any slice type. Returns an empty slice if slices is empty or nil. If only one slice is provided, returns a copy of that slice.

Example:

// Join with separator
slicez.Join([][]int{{1, 2}, {3, 4}, {5, 6}}, []int{0, 0})
// returns []int{1, 2, 0, 0, 3, 4, 0, 0, 5, 6}

// Join strings (like strings.Join but returns []string)
slicez.Join([][]string{{"hello"}, {"world"}}, []string{" "})
// returns []string{"hello", " ", "world"}

// Single slice
slicez.Join([][]int{{1, 2, 3}}, []int{0})
// returns []int{1, 2, 3}

func KeyBy

func KeyBy[A any, B comparable](slice []A, key func(a A) B) map[B]A

KeyBy creates a map indexed by a key function. Each element is indexed by the result of the key function. If multiple elements have the same key, the first one is kept.

Example:

type User struct { ID int; Name string }
users := []User{{1, "Alice"}, {2, "Bob"}, {1, "Charlie"}}
slicez.KeyBy(users, func(u User) int { return u.ID })
// Returns map[int]User{1: {1, "Alice"}, 2: {2, "Bob"}}
// Note: {1, "Charlie"} is skipped because ID 1 already exists

func Last

func Last[A any](slice []A) (A, error)

Last returns the last element of the slice. Returns an error if the slice is empty or nil.

Example:

val, err := slicez.Last([]int{1, 2, 3})
// val = 3, err = nil

val, err := slicez.Last([]string{"a", "b", "c"})
// val = "c", err = nil

val, err := slicez.Last([]int{})
// val = 0 (zero value), err = "slice does not have any elements"

func LastIndex

func LastIndex[E comparable](s []E, needle E) int

LastIndex returns the index of the last occurrence of needle in s. It returns -1 if needle is not found. Uses == comparison for equality.

Example:

slicez.LastIndex([]int{1, 2, 3, 2, 1}, 2)     // returns 3 (last occurrence)
slicez.LastIndex([]string{"a", "b", "c", "b"}, "b") // returns 3
slicez.LastIndex([]int{1, 2, 3}, 4)          // returns -1 (not found)

func LastIndexBy

func LastIndexBy[E any](s []E, f func(E) bool) int

LastIndexBy returns the index of the last element where f returns true. It returns -1 if no element satisfies the condition.

Example:

// Find last even number
slicez.LastIndexBy([]int{2, 4, 6, 7, 8}, func(n int) bool {
    return n%2 == 0
}) // returns 4

// Find last negative number
slicez.LastIndexBy([]int{1, -2, 3, -4, 5}, func(n int) bool {
    return n < 0
}) // returns 3

func Map

func Map[A any, B any](slice []A, f func(a A) B) []B

Map transforms each element of the slice using the provided function. Returns a new slice with the transformed elements. Preserves order.

Example:

// Convert integers to strings
slicez.Map([]int{1, 2, 3}, func(n int) string {
    return fmt.Sprintf("num-%d", n)
})
// Returns []string{"num-1", "num-2", "num-3"}

// Double each number
slicez.Map([]int{1, 2, 3, 4}, func(n int) int { return n * 2 })
// Returns []int{2, 4, 6, 8}

func MapIdx added in v1.2.0

func MapIdx[A any, B any](slice []A, mapper func(index int, a A) B) []B

MapIdx maps a function over the slice with index awareness. The mapper function receives both the index and the element.

Example:

MapIdx([]string{"a", "b", "c"}, func(i int, s string) string {
    return fmt.Sprintf("%d:%s", i, s)
})
// Returns []string{"0:a", "1:b", "2:c"}

func Max

func Max[E compare.Ordered](slice ...E) E

Max returns the largest element from the variadic arguments. Works with any Ordered type. Returns zero value if no arguments provided.

Example:

slicez.Max(3, 1, 4, 1, 5)     // Returns 5
slicez.Max("cherry", "apple") // Returns "cherry" (lexicographic comparison)
slicez.Max([]int{1, 2, 3}...)  // Returns 3 (slice spread)

func Min

func Min[E compare.Ordered](slice ...E) E

Min returns the smallest element from the variadic arguments. Works with any Ordered type. Returns zero value if no arguments provided.

Example:

slicez.Min(3, 1, 4, 1, 5)     // Returns 1
slicez.Min("cherry", "apple") // Returns "apple" (lexicographic comparison)
slicez.Min([]int{3, 2, 1}...)  // Returns 1 (slice spread)

func None

func None[A comparable](slice []A, needle A) bool

None checks if no element equals the given value. Negation of Some/Contains. Returns true if the slice is empty. Uses equality comparison (==).

Example:

slicez.None([]int{1, 2, 3}, 4)     // Returns true (4 not in slice)
slicez.None([]int{1, 2, 3}, 2)     // Returns false (2 is in slice)
slicez.None([]string{"a", "b"}, "c") // Returns true
slicez.None([]int{}, 1)             // Returns true (empty slice)

func NoneBy

func NoneBy[A any](slice []A, predicate func(A) bool) bool

NoneBy checks if no element satisfies the predicate. Negation of SomeBy. Returns true if the slice is empty. Useful for ensuring no elements match a condition.

Example:

// Check no numbers are negative
slicez.NoneBy([]int{1, 2, 3, 4}, func(n int) bool {
    return n < 0
}) // Returns true

// Check no strings are empty
slicez.NoneBy([]string{"a", "b", ""}, func(s string) bool {
    return len(s) == 0
}) // Returns false (empty string exists)

slicez.NoneBy([]int{}, func(n int) bool { return n < 0 })
// Returns true (empty slice)

func Nth

func Nth[A any](slice []A, i int) A

Nth returns the element at the given index with modulo/wraparound support. Supports negative indices (counting from end: -1 = last, -2 = second to last). Supports out-of-bounds positive indices (wraps around using modulo). Returns zero value if slice is empty.

Example:

s := []string{"a", "b", "c", "d"}

slicez.Nth(s, 0)   // Returns "a" (first element)
slicez.Nth(s, 2)   // Returns "c" (third element)
slicez.Nth(s, -1)  // Returns "d" (last element)
slicez.Nth(s, -2)  // Returns "c" (second to last)
slicez.Nth(s, 4)   // Returns "a" (wraps around: 4 % 4 = 0)
slicez.Nth(s, 10)  // Returns "b" (wraps around: 10 % 4 = 2)

func OrderBy added in v1.2.2

func OrderBy[A any, T compare.Ordered](slice []A, selector func(a A) T, order ...func(a, b T) bool) []A

OrderBy sorts a slice by a selected key using a custom comparison function. The selector function extracts the key to sort by from each element. The optional order function controls the sort direction; defaults to ascending (compare.Less). Use compare.Asc or compare.Desc for common sort orders. Returns a new slice; the original is not modified.

Example:

// Sort strings by length (ascending)
words := []string{"banana", "pie", "apple", "kiwi"}
sorted := slicez.OrderBy(words, func(s string) int { return len(s) })
// Returns []string{"pie", "kiwi", "apple", "banana"}

// Sort by length descending
sortedDesc := slicez.OrderBy(words, func(s string) int { return len(s) }, compare.Desc[int])
// Returns []string{"banana", "apple", "kiwi", "pie"}

// Sort people by age
type Person struct { Name string; Age int }
people := []Person{{"Alice", 30}, {"Bob", 25}, {"Charlie", 35}}
sorted := slicez.OrderBy(people, func(p Person) int { return p.Age })
// Returns [{Bob 25} {Alice 30} {Charlie 35}]

func Partition

func Partition[A any](slice []A, predicate func(a A) bool) (satisfied, notSatisfied []A)

Partition splits a slice into two based on a predicate. Returns two slices: one with elements where predicate is true, one where false. Both slices maintain original relative ordering.

Example:

// Separate even and odd numbers
even, odd := slicez.Partition([]int{1, 2, 3, 4, 5, 6}, func(n int) bool {
    return n%2 == 0
})
// even = []int{2, 4, 6}
// odd = []int{1, 3, 5}

// Separate positive and non-positive
pos, nonPos := slicez.Partition([]int{-2, -1, 0, 1, 2}, func(n int) bool {
    return n > 0
})
// pos = []int{1, 2}
// nonPos = []int{-2, -1, 0}

func PartitionBy

func PartitionBy[A any, B comparable](slice []A, by func(a A) B) [][]A

PartitionBy groups elements by key while preserving first-seen key order. Unlike GroupBy, this returns ordered groups instead of a map. Unlike ChunkBy, grouping is not based on adjacency; elements with the same key are grouped together even when they are non-consecutive.

Example:

// Group by value, preserving first key order
slicez.PartitionBy([]int{2, 1, 2, 3, 1}, func(a int) int { return a })
// Returns [][]int{{2, 2}, {1, 1}, {3}}

// Group by first letter
slicez.PartitionBy([]string{"apple", "avocado", "banana", "blueberry", "cherry"},
    func(s string) string { return string(s[0]) })
// Returns [][]string{{"apple", "avocado"}, {"banana", "blueberry"}, {"cherry"}}

// Non-consecutive elements with same key are still grouped together
slicez.PartitionBy([]int{1, 2, 1}, func(a int) int { return a })
// Returns [][]int{{1, 1}, {2}}

func Range added in v1.2.0

func Range(start, end int) []int

Range creates a slice of integers from start to end (inclusive).

Example:

Range(1, 5)   // Returns []int{1, 2, 3, 4, 5}
Range(5, 1)   // Returns []int{} (empty when start > end)
Range(3, 3)   // Returns []int{3}

func RangeFrom added in v1.2.0

func RangeFrom(start, n int) []int

RangeFrom creates a slice of n integers starting from start.

Example:

RangeFrom(0, 5)   // Returns []int{0, 1, 2, 3, 4}
RangeFrom(10, 3)  // Returns []int{10, 11, 12}
RangeFrom(5, 0)   // Returns []int{} (empty when n <= 0)

func RangeStep added in v1.2.0

func RangeStep(start, end, step int) []int

RangeStep creates a slice from start to end with a step value.

Example:

RangeStep(0, 10, 2)   // Returns []int{0, 2, 4, 6, 8, 10}
RangeStep(10, 0, -2)  // Returns []int{10, 8, 6, 4, 2, 0}
RangeStep(0, 10, 3)   // Returns []int{0, 3, 6, 9}

func Reject

func Reject[A any](slice []A, exclude func(a A) bool) []A

Reject returns a new slice containing only elements where the predicate returns false. Complement of Filter - keeps elements that DON'T match the condition. Returns a new slice; the original is not modified.

Example:

// Remove even numbers (keep odd)
slicez.Reject([]int{1, 2, 3, 4, 5, 6}, func(n int) bool {
    return n%2 == 0
})
// Returns []int{1, 3, 5}

// Remove short strings
slicez.Reject([]string{"a", "bb", "ccc", "dddd"}, func(s string) bool {
    return len(s) <= 2
})
// Returns []string{"ccc", "dddd"}

func RejectIdx added in v1.2.0

func RejectIdx[A any](slice []A, exclude func(index int, a A) bool) []A

RejectIdx is the complement of FilterIdx, filtering out elements that satisfy the predicate.

func Repeat added in v1.2.0

func Repeat[A any](slice []A, n int) []A

Repeat repeats the slice n times and returns the concatenated result.

Example:

Repeat([]int{1, 2}, 3)    // Returns []int{1, 2, 1, 2, 1, 2}
Repeat([]string{"a"}, 5)   // Returns []string{"a", "a", "a", "a", "a"}
Repeat([]int{1, 2}, 0)    // Returns []int{} (empty when n <= 0)

func RepeatBy

func RepeatBy[A any](i int, by func(i int) A) []A

RepeatBy creates a slice of length n where each element is computed by the provided function. The function receives the index (0 to n-1) and returns the value for that position. Useful for creating sequences or computed values.

Example:

// Create squares: [0, 1, 4, 9, 16]
slicez.RepeatBy(5, func(i int) int { return i * i })

// Create pattern: [0, 1, 0, 1, 0]
slicez.RepeatBy(5, func(i int) int { return i % 2 })

// Create initialized structs
type Point struct{ X, Y int }
slicez.RepeatBy(3, func(i int) Point { return Point{X: i, Y: i * 10} })
// Returns [{0 0}, {1 10}, {2 20}]

func Replace

func Replace[E comparable](haystack []E, needle E, replacement E, n int) []E

Replace replaces up to n occurrences of needle with replacement in haystack. If n < 0, all occurrences are replaced. Returns a new slice; the original is not modified.

Example:

// Replace first 2 occurrences
slicez.Replace([]int{1, 2, 1, 2, 1}, 1, 99, 2)
// returns []int{99, 2, 99, 2, 1}

// Replace all occurrences (n < 0)
slicez.Replace([]int{1, 2, 1, 2, 1}, 1, 99, -1)
// returns []int{99, 2, 99, 2, 99}

// Replace first occurrence only
slicez.Replace([]string{"a", "b", "a"}, "a", "z", 1)
// returns []string{"z", "b", "a"}

func ReplaceAll

func ReplaceAll[E comparable](haystack []E, needle E, replacement E) []E

ReplaceAll replaces all occurrences of needle with replacement in haystack. Returns a new slice; the original is not modified.

Example:

slicez.ReplaceAll([]int{1, 2, 1, 3, 1}, 1, 99)
// returns []int{99, 2, 99, 3, 99}

func ReplaceFirst

func ReplaceFirst[E comparable](haystack []E, needle E, replacement E) []E

ReplaceFirst replaces the first occurrence of needle with replacement in haystack. Returns a new slice; the original is not modified.

Example:

slicez.ReplaceFirst([]int{1, 2, 1, 3}, 1, 99)
// returns []int{99, 2, 1, 3}

func Reverse

func Reverse[A any](slice []A) []A

Reverse returns a new slice with elements in reverse order. The first element becomes the last, and the last becomes the first. Returns nil for nil input (preserves nil vs empty distinction).

Example:

slicez.Reverse([]int{1, 2, 3, 4, 5})
// Returns []int{5, 4, 3, 2, 1}

slicez.Reverse([]string{"a", "b", "c"})
// Returns []string{"c", "b", "a"}

slicez.Reverse([]int{}) // Returns []int{} (empty)

func Sample

func Sample[A any](slice []A, n int) []A

Sample returns n random elements from the slice without replacement. Uses efficient algorithms based on sample size: Fisher-Yates shuffle for large samples, swap-to-end algorithm for medium slices, and set-based selection for very large slices. Returns fewer elements if n > len(slice). Returns empty slice if n <= 0. The random source is math/rand; consider seeding for non-deterministic results.

Example:

slicez.Sample([]int{1, 2, 3, 4, 5}, 3)
// Might return []int{2, 5, 1} (3 random elements)

slicez.Sample([]string{"a", "b", "c"}, 2)
// Returns 2 random strings from the slice

slicez.Sample([]int{1, 2, 3}, 5)
// Returns []int{1, 2, 3} (all elements, n > len)

func Scan added in v1.2.0

func Scan[I any, A any](slice []I, combine func(accumulator A, val I) A, init A) []A

Scan is an alias for ScanLeft.

func ScanLeft added in v1.2.0

func ScanLeft[I any, A any](slice []I, combine func(accumulator A, val I) A, init A) []A

ScanLeft returns all intermediate results of folding from left to right. Like Fold but returns all accumulator values including the initial value.

Example:

ScanLeft([]int{1, 2, 3}, func(acc, val int) int { return acc + val }, 0)
// Returns []int{0, 1, 3, 6} (running sums)

func ScanRight added in v1.2.0

func ScanRight[I any, A any](slice []I, combine func(accumulator A, val I) A, init A) []A

ScanRight returns all intermediate results of folding from right to left. Like ScanLeft but operates from right to left.

Example:

ScanRight([]int{1, 2, 3}, func(acc, val int) int { return acc + val }, 0)
// Returns []int{0, 3, 5, 6} (running sums from right)
func Search[A any](slice []A, f func(e A) bool) (index int, e A)

Search performs binary search on a monotonic predicate over a slice. Returns the smallest index i where f(slice[i]) is true. Predicate f must be false for a (possibly empty) prefix, then true afterwards. If no element satisfies f, returns len(slice) and the zero value.

Example:

// Find first element >= 23
idx, val := slicez.Search([]int{10, 20, 30, 40, 50}, func(e int) bool {
    return e >= 23
})
// Returns (2, 30) - index 2 has value 30

// Find insertion point for 25 (maintaining sorted order)
idx, _ := slicez.Search([]int{10, 20, 30, 40}, func(e int) bool {
    return e >= 25
})
// Returns 2 - insert 25 at index 2

func Set

func Set[E comparable](slice []E) map[E]bool

Set creates a set (as map[E]bool) from a slice. Returns a map where keys are slice elements and values are true. Useful for O(1) membership testing.

Example:

set := slicez.Set([]int{1, 2, 3, 2, 1})
// Returns map[int]bool{1: true, 2: true, 3: true}

// Check membership
if set[2] {
    fmt.Println("2 is in the set")
}

Note: For more set operations, consider using the setz package.

func Shuffle

func Shuffle[A any](slice []A) []A

Shuffle returns a new slice with elements in random order. Uses Fisher-Yates shuffle algorithm for uniform random distribution. Returns a copy; the original slice is not modified. The random source is math/rand; consider seeding for non-deterministic results.

Example:

slicez.Shuffle([]int{1, 2, 3, 4, 5})
// Might return []int{3, 1, 5, 2, 4} (random order)

slicez.Shuffle([]string{"a", "b", "c", "d"})
// Returns strings in random order

// Empty slice
slicez.Shuffle([]int{}) // Returns []int{}

func SliceToMap

func SliceToMap[E any, K comparable, V any](slice []E, mapper func(a E) (key K, value V)) map[K]V

SliceToMap converts a slice to a map using a mapper function. Each element is transformed into a key-value pair. Later elements overwrite earlier ones if keys collide.

Example:

// Create map from id to name
type User struct { ID int; Name string }
users := []User{{1, "Alice"}, {2, "Bob"}}
slicez.SliceToMap(users, func(u User) (int, string) {
    return u.ID, u.Name
})
// Returns map[int]string{1: "Alice", 2: "Bob"}

Alias for Associate.

func SlidingWindow added in v1.2.0

func SlidingWindow[A any](slice []A, n int) [][]A

SlidingWindow creates sliding windows of size n from the slice. Returns a slice of slices where each inner slice has n consecutive elements.

Example:

SlidingWindow([]int{1, 2, 3, 4, 5}, 3)
// Returns [][]int{{1, 2, 3}, {2, 3, 4}, {3, 4, 5}}

func Some

func Some[A comparable](slice []A, needle A) bool

Some checks if any element equals the given value. Alias for Contains. Returns false if the slice is empty. Uses equality comparison (==).

Example:

slicez.Some([]int{1, 2, 3}, 2)     // Returns true
slicez.Some([]int{1, 2, 3}, 4)     // Returns false
slicez.Some([]string{"a", "b"}, "c") // Returns false
slicez.Some([]int{}, 1)            // Returns false (empty slice)

func SomeBy

func SomeBy[A any](slice []A, predicate func(A) bool) bool

SomeBy checks if any element satisfies the predicate. Returns false if the slice is empty. Alias for ContainsBy.

Example:

// Check if any number is even
slicez.SomeBy([]int{1, 3, 5, 6, 7}, func(n int) bool {
    return n%2 == 0
}) // Returns true (6 is even)

// Check if any string is longer than 5 chars
slicez.SomeBy([]string{"a", "bb", "ccc"}, func(s string) bool {
    return len(s) > 5
}) // Returns false

slicez.SomeBy([]int{}, func(n int) bool { return n > 0 })
// Returns false (empty slice)

func Sort

func Sort[A compare.Ordered](slice []A) []A

Sort returns a new slice with elements sorted in natural ascending order. Uses Go's sort.Slice internally. Returns a copy; the original slice is not modified. Works with any Ordered type (integers, floats, strings).

Example:

slicez.Sort([]int{3, 1, 4, 1, 5, 9, 2, 6})
// Returns []int{1, 1, 2, 3, 4, 5, 6, 9}

slicez.Sort([]string{"cherry", "apple", "banana"})
// Returns []string{"apple", "banana", "cherry"}

func SortBy

func SortBy[A any](slice []A, less func(a, b A) bool) []A

SortBy returns a new slice sorted using a custom comparison function. The less function should return true if a should come before b. Returns a copy; the original slice is not modified.

Example:

// Sort by string length
slicez.SortBy([]string{"aaa", "bb", "c", "dddd"}, func(a, b string) bool {
    return len(a) < len(b)
})
// Returns []string{"c", "bb", "aaa", "dddd"}

// Sort structs by age field
type Person struct { Name string; Age int }
people := []Person{{"Alice", 30}, {"Bob", 25}, {"Charlie", 35}}
slicez.SortBy(people, func(a, b Person) bool {
    return a.Age < b.Age
})
// Returns [{Bob 25} {Alice 30} {Charlie 35}]

func Span added in v1.2.0

func Span[A any](slice []A, predicate func(a A) bool) (init, rest []A)

Span splits the slice at the first element that does not satisfy the predicate. Returns two slices: elements satisfying the predicate, and remaining elements. More efficient than calling TakeWhile + DropWhile separately.

Example:

Span([]int{1, 2, 3, 4, 5}, func(n int) bool { return n < 4 })
// Returns ([]int{1, 2, 3}, []int{4, 5})

func SplitAt added in v1.2.0

func SplitAt[A any](slice []A, index int) (before, after []A)

SplitAt splits the slice at the given index. Returns two slices: elements before index and elements from index onward.

Example:

SplitAt([]int{1, 2, 3, 4, 5}, 2)
// Returns ([]int{1, 2}, []int{3, 4, 5})

func Tail

func Tail[A any](slice []A) []A

Tail returns a new slice containing all elements except the first. Returns nil if the slice has 0 or 1 elements. Useful for recursive processing (head:tail pattern).

Example:

slicez.Tail([]int{1, 2, 3, 4})
// Returns []int{2, 3, 4}

slicez.Tail([]string{"a", "b"})
// Returns []string{"b"}

slicez.Tail([]int{1}) // Returns nil

func Take

func Take[A any](slice []A, i int) []A

Take returns the first i elements of the slice. If i > len(slice), returns a copy of the entire slice. If i <= 0, returns a zero-length slice (which may be nil).

Example:

slicez.Take([]int{1, 2, 3, 4, 5}, 3)
// Returns []int{1, 2, 3}

slicez.Take([]string{"a", "b", "c", "d"}, 2)
// Returns []string{"a", "b"}

slicez.Take([]int{1, 2, 3}, 10)
// Returns []int{1, 2, 3} (all elements)

slicez.Take([]int{1, 2, 3}, 0) // Returns []int{} (zero-length)

func TakeRight

func TakeRight[A any](slice []A, i int) []A

TakeRight returns the last i elements of the slice. If i > len(slice), returns a copy of the entire slice. If i <= 0, returns a zero-length slice (which may be nil).

Example:

slicez.TakeRight([]int{1, 2, 3, 4, 5}, 3)
// Returns []int{3, 4, 5}

slicez.TakeRight([]string{"a", "b", "c", "d"}, 2)
// Returns []string{"c", "d"}

slicez.TakeRight([]int{1, 2, 3}, 10)
// Returns []int{1, 2, 3} (all elements)

slicez.TakeRight([]int{1, 2, 3}, 0) // Returns []int{} (zero-length)

func TakeRightWhile

func TakeRightWhile[A any](slice []A, take func(a A) bool) []A

TakeRightWhile returns elements from the end while the predicate returns true. Stops at the first element (from the right) where the predicate returns false. Returns a new slice; the original is not modified.

Example:

// Take from right while greater than 5
slicez.TakeRightWhile([]int{1, 2, 6, 7, 8, 3, 4}, func(n int) bool {
    return n > 5
})
// Returns []int{6, 7, 8} (stops at 3)

// Take strings ending with vowel from right
slicez.TakeRightWhile([]string{"cat", "dog", "bee", "flea"}, func(s string) bool {
    return strings.ContainsRune("aeiou", rune(s[len(s)-1]))
})
// Returns []string{"bee", "flea"}

func TakeWhile

func TakeWhile[A any](slice []A, take func(a A) bool) []A

TakeWhile returns elements from the start while the predicate returns true. Stops at the first element where the predicate returns false. Returns a new slice; the original is not modified.

Example:

// Take while less than 4
slicez.TakeWhile([]int{1, 2, 3, 4, 5}, func(n int) bool {
    return n < 4
})
// Returns []int{1, 2, 3}

// Take while strings start with "a"
slicez.TakeWhile([]string{"apple", "avocado", "banana", "apricot"}, func(s string) bool {
    return strings.HasPrefix(s, "a")
})
// Returns []string{"apple", "avocado"}

func Transpose added in v1.2.0

func Transpose[A any](matrix [][]A) [][]A

Transpose transposes a matrix (slice of slices), swapping rows and columns. Assumes all rows have the same length. Returns nil for empty input.

Example:

Transpose([][]int{{1, 2, 3}, {4, 5, 6}})
// Returns [][]int{{1, 4}, {2, 5}, {3, 6}}

func Union

func Union[A comparable](slices ...[]A) []A

Union returns the set union of multiple slices. Combines all unique elements from all slices, preserving order of first appearance. Equivalent to Uniq(Concat(slices...)).

Example:

slicez.Union([]int{1, 2, 3}, []int{2, 3, 4}, []int{3, 4, 5})
// Returns []int{1, 2, 3, 4, 5}

slicez.Union([]string{"a", "b"}, []string{"c"}, []string{"a", "d"})
// Returns []string{"a", "b", "c", "d"}

func UnionBy

func UnionBy[A any, B comparable](by func(a A) B, slices ...[]A) []A

UnionBy returns the set union using a key function. Elements are considered equal if they have the same key. Preserves order of first appearance of each unique key.

Example:

type Person struct { Name string; Age int }
a := []Person{{"Alice", 30}, {"Bob", 25}}
b := []Person{{"Charlie", 30}, {"Dave", 35}}
slicez.UnionBy(func(p Person) int { return p.Age }, a, b)
// Returns [{Alice 30} {Bob 25} {Dave 35}]
// Charlie is excluded because age 30 already seen

func Uniq

func Uniq[A comparable](slice []A) []A

Uniq removes all duplicate elements from a slice, keeping the first occurrence. Uses equality comparison (==) for comparable types. Preserves order.

Example:

slicez.Uniq([]int{1, 2, 2, 3, 1, 4})
// Returns []int{1, 2, 3, 4}

slicez.Uniq([]string{"a", "b", "a", "c", "b"})
// Returns []string{"a", "b", "c"}

func UniqBy

func UniqBy[A any, B comparable](slice []A, by func(a A) B) []A

UniqBy removes duplicates using a key function, keeping the first occurrence. Elements are considered duplicates if they have the same key. Preserves order.

Example:

// Uniq by string length
slicez.UniqBy([]string{"hi", "go", "no", "hello", "hey"}, func(s string) int {
    return len(s)
})
// Returns []string{"hi", "hello"} (2-letter and 5-letter strings)

// Uniq by age
type Person struct { Name string; Age int }
people := []Person{{"Alice", 30}, {"Bob", 25}, {"Charlie", 30}}
slicez.UniqBy(people, func(p Person) int { return p.Age })
// Returns [{Alice 30} {Bob 25}]

func Unzip

func Unzip[A any, B any, C any](cSlice []C, unzipper func(c C) (a A, b B)) ([]A, []B)

Unzip splits a slice of pairs into two separate slices. Inverse operation of Zip. Both returned slices have the same length as input.

Example:

// Split pairs into components
pairs := []struct{ X, Y int }{{1, 10}, {2, 20}, {3, 30}}
xs, ys := slicez.Unzip(pairs, func(p struct{ X, Y int }) (int, int) {
    return p.X, p.Y
})
// xs = []int{1, 2, 3}, ys = []int{10, 20, 30}

// Unzip strings to bytes
slicez.Unzip([]string{"hi", "go"}, func(s string) (rune, rune) {
    return rune(s[0]), rune(s[1])
})
// Returns ([]rune{'h', 'g'}, []rune{'i', 'o'})

func Unzip2

func Unzip2[A any, B any, C any, D any](dSlice []D, unzipper func(d D) (a A, b B, c C)) ([]A, []B, []C)

Unzip2 splits a slice of triples into three separate slices. Inverse operation of Zip2. All returned slices have the same length.

Example:

// Split RGB values
colors := []struct{ R, G, B uint8 }{{255, 0, 0}, {0, 255, 0}, {0, 0, 255}}
rs, gs, bs := slicez.Unzip2(colors, func(c struct{ R, G, B uint8 }) (uint8, uint8, uint8) {
    return c.R, c.G, c.B
})
// rs = []uint8{255, 0, 0}, gs = []uint8{0, 255, 0}, bs = []uint8{0, 0, 255}

func Unzip3

func Unzip3[A any, B any, C any, D any, E any](eSlice []E, unzipper func(e E) (a A, b B, c C, d D)) ([]A, []B, []C, []D)

Unzip3 splits a slice of quadruples into four separate slices. Inverse operation of Zip3. All returned slices have the same length.

Example:

// Split 4D coordinates
coords := []struct{ X, Y, Z, W float64 }{{1, 2, 3, 4}, {5, 6, 7, 8}}
xs, ys, zs, ws := slicez.Unzip3(coords, func(c struct{ X, Y, Z, W float64 }) (float64, float64, float64, float64) {
    return c.X, c.Y, c.Z, c.W
})
// xs = []float64{1, 5}, ys = []float64{2, 6}, zs = []float64{3, 7}, ws = []float64{4, 8}

func Without

func Without[A comparable](slice []A, exclude ...A) []A

Without returns a new slice with all specified values removed. Excludes all occurrences of each value in exclude. Uses equality comparison (==). Returns a new slice; the original is not modified.

Example:

slicez.Without([]int{1, 2, 3, 2, 4, 2, 5}, 2)
// Returns []int{1, 3, 4, 5} (all 2s removed)

slicez.Without([]string{"a", "b", "a", "c", "a"}, "a")
// Returns []string{"b", "c"}

// Remove multiple values
slicez.Without([]int{1, 2, 3, 4, 5}, 2, 4)
// Returns []int{1, 3, 5}

slicez.Without([]int{1, 2, 3}) // Returns []int{1, 2, 3} (unchanged copy)

func XOR

func XOR[A comparable](slices ...[]A) []A

XOR returns elements whose key appears exactly once across all inputs. Duplicate values within a single slice also count toward that frequency. Output order follows input traversal.

Example:

slicez.XOR([]int{1, 2, 3}, []int{2, 3, 4})
// Returns []int{1, 4} (2 and 3 appear in both, so excluded)

slicez.XOR([]int{1, 2, 2}, []int{2, 3})
// Returns []int{1, 3} (2 appears three times total, so excluded)

func XORBy

func XORBy[A any, B comparable](by func(A) B, slices ...[]A) []A

XORBy is XOR with custom key extraction. A key is included only if it appears exactly once across all slices.

Example:

type Person struct { Name string; Age int }
a := []Person{{"Alice", 30}, {"Bob", 25}}
b := []Person{{"Charlie", 30}, {"Dave", 35}}
slicez.XORBy(func(p Person) int { return p.Age }, a, b)
// Returns [{Bob 25} {Dave 35}] (age 30 in both, ages 25 and 35 unique)

func Zip

func Zip[A any, B any, C any](aSlice []A, bSlice []B, zipper func(a A, b B) C) []C

Zip combines two slices element-wise using a zipper function. Stops at the length of the shorter slice. Returns empty slice if either input is empty.

Example:

// Pair elements
slicez.Zip([]int{1, 2, 3}, []string{"a", "b", "c"}, func(n int, s string) string {
    return fmt.Sprintf("%d:%s", n, s)
})
// Returns []string{"1:a", "2:b", "3:c"}

// Add corresponding elements
slicez.Zip([]int{1, 2, 3}, []int{10, 20, 30}, func(a, b int) int {
    return a + b
})
// Returns []int{11, 22, 33}

// Different lengths (truncated)
slicez.Zip([]int{1, 2, 3, 4}, []string{"a", "b"}, func(n int, s string) string {
    return s + strconv.Itoa(n)
})
// Returns []string{"a1", "b2"} (extra elements ignored)

func Zip2

func Zip2[A any, B any, C any, D any](aSlice []A, bSlice []B, cSlice []C, zipper func(a A, b B, c C) D) []D

Zip2 combines three slices element-wise using a zipper function. Like Zip but for three slices. Stops at length of shortest slice.

Example:

// Combine three number sequences
slicez.Zip2([]int{1, 2}, []int{10, 20}, []int{100, 200}, func(a, b, c int) int {
    return a + b + c
})
// Returns []int{111, 222}

// Create structured data
type Point struct{ X, Y, Z int }
slicez.Zip2([]int{1, 2}, []int{3, 4}, []int{5, 6}, func(x, y, z int) Point {
    return Point{x, y, z}
})
// Returns []Point{{1,3,5}, {2,4,6}}

func Zip3

func Zip3[A any, B any, C any, D any, E any](aSlice []A, bSlice []B, cSlice []C, dSlice []D, zipper func(a A, b B, c C, d D) E) []E

Zip3 combines four slices element-wise using a zipper function. Like Zip and Zip2 but for four slices. Stops at length of shortest slice.

Example:

// Combine four number sequences
a, b, c, d := []int{1, 2}, []int{10, 20}, []int{100, 200}, []int{1000, 2000}
slicez.Zip3(a, b, c, d, func(w, x, y, z int) int {
    return w + x + y + z
})
// Returns []int{1111, 2222}

Types

type GroupByEntry added in v1.2.0

type GroupByEntry[K comparable, V any] struct {
	Key    K
	Values []V
}

GroupByEntry represents a single entry in a grouped result with preserved order.

func GroupByOrdered added in v1.2.0

func GroupByOrdered[A any, K comparable](slice []A, by func(A) K) []GroupByEntry[K, A]

GroupByOrdered groups slice elements by a key function while preserving insertion order. Unlike GroupBy which returns a map (with random iteration), this returns a slice where the order of groups matches the order keys first appear in the input.

Example:

words := []string{"apple", "banana", "avocado", "blueberry", "cherry"}
GroupByOrdered(words, func(s string) string { return string(s[0]) })
// Returns []GroupByEntry{{"a", ["apple", "avocado"]}, {"b", ["banana", "blueberry"]}, {"c", ["cherry"]}}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL