slice

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Apr 5, 2026 License: Apache-2.0 Imports: 2 Imported by: 10

Documentation

Overview

Package slice provides functional abstractions over go slices.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func All

func All[T any](in []T, matchFn MatchFn[T]) bool

All returns true if all elements in the input slice are true according to the provided matchFn.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	// Function to check if an element is even
	isEven := func(x int) bool {
		return x%2 == 0
	}

	allEven := []int{2, 4, 6, 8, 10}
	fmt.Printf("All(%v) == %v\n", allEven, slice.All(allEven, isEven))

	withOds := []int{2, 4, 5, 6}
	fmt.Printf("All(%v) == %v\n", withOds, slice.All(withOds, isEven))

}
Output:
All([2 4 6 8 10]) == true
All([2 4 5 6]) == false

func Any

func Any[T any](in []T, matchFn MatchFn[T]) bool

Any returns true if any of the elements in the input slice return true when the provided matchFn is called.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	// Function to check if an element is seven
	isSeven := func(x int) bool {
		return x == 7
	}

	noSevens := []int{5, 6, 8}
	fmt.Printf("All(%v) == %v\n", noSevens, slice.Any(noSevens, isSeven))

	withSevens := []int{5, 6, 7, 8}
	fmt.Printf("All(%v) == %v\n", withSevens, slice.Any(withSevens, isSeven))

}
Output:
All([5 6 8]) == false
All([5 6 7 8]) == true

func ChunkBy added in v1.0.0

func ChunkBy[T any, K comparable](in []T, keyFn KeyFn[T, K]) [][]T

ChunkBy splits in into consecutive chunks where all elements in a chunk return the same key according to keyFn. A new chunk begins each time the key changes.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := []int{1, 3, 2, 4, 5}
	isEven := func(x int) bool { return x%2 == 0 }
	fmt.Printf("%v\n", slice.ChunkBy(in, isEven))
}
Output:
[[1 3] [2 4] [5]]

func ChunkEvery added in v1.0.0

func ChunkEvery[T any](in []T, n int) [][]T

ChunkEvery splits in into consecutive non-overlapping chunks of size n. The final chunk may be smaller than n if len(in) is not evenly divisible. Returns an empty slice if n <= 0 or in is empty.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := []int{1, 2, 3, 4, 5}
	fmt.Printf("%v\n", slice.ChunkEvery(in, 2))
}
Output:
[[1 2] [3 4] [5]]

func Dedup added in v1.0.0

func Dedup[T comparable](in []T) []T

Dedup removes consecutive duplicate elements from in, keeping the first occurrence of each run. Only adjacent duplicates are removed; use Frequencies or a sort before Dedup to remove all duplicates.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := []int{1, 1, 2, 3, 3, 3, 2}
	fmt.Printf("%v\n", slice.Dedup(in))
}
Output:
[1 2 3 2]

func DedupBy added in v1.0.0

func DedupBy[T any, K comparable](in []T, keyFn KeyFn[T, K]) []T

DedupBy removes consecutive elements from in that produce the same key according to keyFn, keeping the first element of each run.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := []int{1, 3, 2, 4, 5}
	isEven := func(x int) bool { return x%2 == 0 }
	fmt.Printf("%v\n", slice.DedupBy(in, isEven))
}
Output:
[1 2 5]

func Filter added in v0.3.0

func Filter[T any](in []T, matchFn MatchFn[T]) []T

Filter returns a new slice of only the elements in the list that match the provided matchFn.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	type Account struct {
		Name   string
		Writer bool
	}

	input := []*Account{
		{
			Name:   "Bob",
			Writer: false,
		},
		{
			Name:   "Alice",
			Writer: true,
		},
		{
			Name:   "Steve",
			Writer: false,
		},
	}

	// Function to check if an element is even
	isWriter := func(x *Account) bool {
		return x.Writer
	}

	writers := slice.Filter(input, isWriter)
	fmt.Printf("Writers:\n")
	for _, writer := range writers {
		fmt.Printf(" - name: %v\n", writer.Name)
	}

	isReadOnly := func(x *Account) bool {
		return !x.Writer
	}

	readers := slice.Filter(input, isReadOnly)
	fmt.Printf("Readers:\n")
	for _, reader := range readers {
		fmt.Printf(" - name: %v\n", reader.Name)
	}

}
Output:
Writers:
 - name: Alice
Readers:
 - name: Bob
 - name: Steve

func Find added in v1.0.0

func Find[T any](in []T, matchFn MatchFn[T]) (T, bool)

Find returns the first element in in for which matchFn returns true, and a boolean indicating whether a match was found. If no element matches, the zero value of T and false are returned.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	isEven := func(x int) bool { return x%2 == 0 }
	in := []int{1, 3, 4, 6}
	val, found := slice.Find(in, isEven)
	fmt.Printf("Find even in %v: val=%v found=%v\n", in, val, found)

	noMatch := []int{1, 3, 5}
	val, found = slice.Find(noMatch, isEven)
	fmt.Printf("Find even in %v: val=%v found=%v\n", noMatch, val, found)
}
Output:
Find even in [1 3 4 6]: val=4 found=true
Find even in [1 3 5]: val=0 found=false

func FindIndex added in v1.0.0

func FindIndex[T any](in []T, matchFn MatchFn[T]) (int, bool)

FindIndex returns the index of the first element in in for which matchFn returns true, and a boolean indicating whether a match was found. If no element matches, -1 and false are returned.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	isEven := func(x int) bool { return x%2 == 0 }
	in := []int{1, 3, 4, 6}
	idx, found := slice.FindIndex(in, isEven)
	fmt.Printf("FindIndex even in %v: idx=%v found=%v\n", in, idx, found)

	noMatch := []int{1, 3, 5}
	idx, found = slice.FindIndex(noMatch, isEven)
	fmt.Printf("FindIndex even in %v: idx=%v found=%v\n", noMatch, idx, found)
}
Output:
FindIndex even in [1 3 4 6]: idx=2 found=true
FindIndex even in [1 3 5]: idx=-1 found=false

func FlatMap added in v1.0.0

func FlatMap[T any, R any](in []T, fn FlatMapFn[T, R]) []R

FlatMap applies fn to each element of in and concatenates the resulting slices into a single slice of type R.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	words := []string{"hello world", "foo bar"}
	split := func(s string) []string { return strings.Split(s, " ") }
	got := slice.FlatMap(words, split)
	fmt.Printf("%v\n", got)
}
Output:
[hello world foo bar]

func Flatten added in v1.0.0

func Flatten[T any](in [][]T) []T

Flatten takes a slice of slices and concatenates them into a single slice.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := [][]int{{1, 2}, {3, 4}, {5}}
	got := slice.Flatten(in)
	fmt.Printf("%v\n", got)
}
Output:
[1 2 3 4 5]

func FoldL

func FoldL[T any, A any](in []T, acc A, fn AccFn[T, A]) A

FoldL folds (reduces) the input slice from the left. Requires an initial accumulator and an accumulator function.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	sumFn := func(x int, acc int) int {
		return acc + x
	}

	in := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	sum := slice.FoldL(in, 0, sumFn)

	fmt.Printf("sum(%v) == %v\n", in, sum)

}
Output:
sum([1 2 3 4 5 6 7 8 9 10]) == 55

func FoldR

func FoldR[T any, A any](in []T, acc A, fn AccFn[T, A]) A

FoldR folds (reduces) the input slice from the right. Requires an initial accumulator and an accumulator function.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	subFn := func(x int, acc int) int {
		return acc - x
	}

	in := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	sum := slice.FoldR(in, 20, subFn)

	fmt.Printf("foldr_sub(%v) == %v\n", in, sum)

}
Output:
foldr_sub([1 2 3 4 5 6 7 8 9 10]) == -35

func Frequencies

func Frequencies[T comparable](in []T) map[T]int

Frequencies returns a map with a count of the number of time each element occurs in the input slice.

func FrequenciesBy

func FrequenciesBy[T any, R comparable](in []T, keyFn KeyFn[T, R]) map[R]int

FrequenciesBy returns a map with a count of the number of times each key occurred in the input sequence. The KeyFn provided can manipulate the input elements in any way.

func GroupBy

func GroupBy[T any, R comparable](in []T, keyFn KeyFn[T, R]) map[R][]T

GroupBy groups the input slice according to the key function.

func Map

func Map[T any, R any](in []T, fn MapFn[T, R]) []R

Map takes in a slice of type T, and a map function that can turn elements of type T into elements of type R. A new slice of type R is returned, withe the map function applied to each element in the input.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

type Person struct {
	Name string
	Age  int
}

func (p Person) String() string {
	return fmt.Sprintf("%s: %v", p.Name, p.Age)
}

func main() {
	redactAge := func(p Person) Person {
		return Person{
			Name: p.Name,
		}
	}

	people := []Person{
		{Name: "Jim", Age: 28},
		{Name: "Dwight", Age: 32},
	}

	redacted := slice.Map(people, redactAge)

	fmt.Printf("%+v\n", people)
	fmt.Printf("%+v\n", redacted)

}
Output:
[Jim: 28 Dwight: 32]
[Jim: 0 Dwight: 0]

func MapToPtr added in v0.2.0

func MapToPtr[T any](in []T) []*T

MapToPtr transforms a slice into a slice of pointers to the same elements.

func MaxBy added in v1.0.0

func MaxBy[T any, K cmp.Ordered](in []T, keyFn func(T) K) (T, bool)

MaxBy returns the element of in with the largest key according to keyFn, and true. Returns the zero value of T and false if in is empty. When multiple elements share the maximum key, the first is returned.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	type person struct {
		Name string
		Age  int
	}
	people := []person{{"Bob", 30}, {"Alice", 20}, {"Carol", 40}}
	oldest, _ := slice.MaxBy(people, func(p person) int { return p.Age })
	fmt.Printf("%s: %d\n", oldest.Name, oldest.Age)
}
Output:
Carol: 40

func MinBy added in v1.0.0

func MinBy[T any, K cmp.Ordered](in []T, keyFn func(T) K) (T, bool)

MinBy returns the element of in with the smallest key according to keyFn, and true. Returns the zero value of T and false if in is empty. When multiple elements share the minimum key, the first is returned.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	type person struct {
		Name string
		Age  int
	}
	people := []person{{"Bob", 30}, {"Alice", 20}, {"Carol", 40}}
	youngest, _ := slice.MinBy(people, func(p person) int { return p.Age })
	fmt.Printf("%s: %d\n", youngest.Name, youngest.Age)
}
Output:
Alice: 20

func Partition added in v1.0.0

func Partition[T any](in []T, matchFn MatchFn[T]) ([]T, []T)

Partition splits in into two slices in a single pass: the first return value contains elements for which matchFn returns true, the second contains the rest. It is equivalent to calling Filter and Reject together without iterating twice.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	isEven := func(x int) bool { return x%2 == 0 }
	in := []int{1, 2, 3, 4, 5, 6}
	evens, odds := slice.Partition(in, isEven)
	fmt.Printf("Evens: %v\n", evens)
	fmt.Printf("Odds:  %v\n", odds)
}
Output:
Evens: [2 4 6]
Odds:  [1 3 5]

func Reject added in v1.0.0

func Reject[T any](in []T, matchFn MatchFn[T]) []T

Reject returns a new slice of only the elements in the list that do NOT match the provided matchFn. It is the complement of Filter.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	isEven := func(x int) bool { return x%2 == 0 }
	in := []int{1, 2, 3, 4, 5, 6}
	odds := slice.Reject(in, isEven)
	fmt.Printf("Reject evens from %v: %v\n", in, odds)
}
Output:
Reject evens from [1 2 3 4 5 6]: [1 3 5]

func Scan added in v1.0.0

func Scan[T any, A any](in []T, acc A, fn AccFn[T, A]) []A

Scan is like FoldL but returns a slice of all intermediate accumulator values, including the initial value. The result always has len(in)+1 elements, with the first element being the initial accumulator.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := []int{1, 2, 3, 4, 5}
	sums := slice.Scan(in, 0, func(v, acc int) int { return acc + v })
	fmt.Printf("%v\n", sums)
}
Output:
[0 1 3 6 10 15]

func SortBy added in v1.0.0

func SortBy[T any, K cmp.Ordered](in []T, keyFn func(T) K) []T

SortBy returns a new slice sorted in ascending order by the key returned by keyFn. The original slice is not modified.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	type person struct {
		Name string
		Age  int
	}
	people := []person{{"Bob", 30}, {"Alice", 20}, {"Carol", 40}}
	sorted := slice.SortBy(people, func(p person) int { return p.Age })
	for _, p := range sorted {
		fmt.Printf("%s: %d\n", p.Name, p.Age)
	}
}
Output:
Alice: 20
Bob: 30
Carol: 40

func Take

func Take[T any](in []T, amount int) []T

Take returns an amount of elements from the beginning of a slice. If the amount provides is negative, it returns that amount of elements from the end of the slice. If the amount is zero, an empty slice is returned.

func TakeEvery

func TakeEvery[T any](in []T, n uint) []T

TakeEvery returns a new slice with every nth element from the original slice. The first element is always included unless n is 0.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	takeTwo := slice.TakeEvery(in, 2)
	fmt.Printf("Take 2: %+v\n", takeTwo)

	takeZero := slice.TakeEvery(in, 0)
	fmt.Printf("Take 0: %+v\n", takeZero)

	takeAll := slice.TakeEvery(in, 27)
	fmt.Printf("Take all: %+v\n", takeAll)

}
Output:
Take 2: [1 3 5 7 9]
Take 0: []
Take all: [1]

func TakeWhile

func TakeWhile[T any](in []T, fn MatchFn[T]) []T

TakeWhile returns elements from the beginning of the input slice as long as the provided MatchFn returns true.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	in := []string{"dip", "drive", "dodge", "swerve"}

	dPrefix := slice.TakeWhile(in, func(s string) bool {
		return strings.HasPrefix(s, "d")
	})
	fmt.Printf("dPrefix: %+v\n", dPrefix)

	diPrefix := slice.TakeWhile(in, func(s string) bool {
		return strings.HasPrefix(s, "di")
	})
	fmt.Printf("diPrefix: %+v\n", diPrefix)

	sPrefix := slice.TakeWhile(in, func(s string) bool {
		return strings.HasPrefix(s, "s")
	})
	fmt.Printf("sPrefix: %+v\n", sPrefix)

	all := slice.TakeWhile(in, func(_ string) bool { return true })
	fmt.Printf("all: %+v\n", all)

}
Output:
dPrefix: [dip drive dodge]
diPrefix: [dip]
sPrefix: []
all: [dip drive dodge swerve]

func Unzip added in v1.0.0

func Unzip[A any, B any](in []Pair[A, B]) ([]A, []B)

Unzip splits a slice of Pairs into two separate slices.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	pairs := []slice.Pair[string, int]{
		{First: "Alice", Second: 95},
		{First: "Bob", Second: 87},
	}
	names, scores := slice.Unzip(pairs)
	fmt.Printf("Names:  %v\n", names)
	fmt.Printf("Scores: %v\n", scores)
}
Output:
Names:  [Alice Bob]
Scores: [95 87]

Types

type AccFn

type AccFn[T any, A any] func(T, A) A

AccFn is the type of the accumulator function, used on various fold operations.

type FlatMapFn added in v1.0.0

type FlatMapFn[T any, R any] func(T) []R

FlatMapFn maps an individual instance of type T into a slice of type R.

type KeyFn

type KeyFn[T any, R comparable] func(T) R

KeyFn determines how the input value should be used when determining frequencies.

type MapFn

type MapFn[T any, R any] func(T) R

MapFn maps an individual instance of a type T into an individual instance of type R.

type MatchFn

type MatchFn[T any] func(T) bool

MatchFn indicates if an element of a slice matches the inclusion function.

type Pair added in v1.0.0

type Pair[A any, B any] struct {
	First  A
	Second B
}

Pair holds two values of potentially different types.

func Zip added in v1.0.0

func Zip[A any, B any](a []A, b []B) []Pair[A, B]

Zip combines two slices into a slice of Pairs. The result length equals the length of the shorter input slice.

Example
package main

import (
	"fmt"

	"github.com/mikehelmick/go-functional/slice"
)

func main() {
	names := []string{"Alice", "Bob", "Carol"}
	scores := []int{95, 87, 92}
	pairs := slice.Zip(names, scores)
	for _, p := range pairs {
		fmt.Printf("%s: %d\n", p.First, p.Second)
	}
}
Output:
Alice: 95
Bob: 87
Carol: 92

Jump to

Keyboard shortcuts

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