Documentation
¶
Overview ¶
Package slice provides functional abstractions over go slices.
Index ¶
- func All[T any](in []T, matchFn MatchFn[T]) bool
- func Any[T any](in []T, matchFn MatchFn[T]) bool
- func ChunkBy[T any, K comparable](in []T, keyFn KeyFn[T, K]) [][]T
- func ChunkEvery[T any](in []T, n int) [][]T
- func Dedup[T comparable](in []T) []T
- func DedupBy[T any, K comparable](in []T, keyFn KeyFn[T, K]) []T
- func Filter[T any](in []T, matchFn MatchFn[T]) []T
- func Find[T any](in []T, matchFn MatchFn[T]) (T, bool)
- func FindIndex[T any](in []T, matchFn MatchFn[T]) (int, bool)
- func FlatMap[T any, R any](in []T, fn FlatMapFn[T, R]) []R
- func Flatten[T any](in [][]T) []T
- func FoldL[T any, A any](in []T, acc A, fn AccFn[T, A]) A
- func FoldR[T any, A any](in []T, acc A, fn AccFn[T, A]) A
- func Frequencies[T comparable](in []T) map[T]int
- func FrequenciesBy[T any, R comparable](in []T, keyFn KeyFn[T, R]) map[R]int
- func GroupBy[T any, R comparable](in []T, keyFn KeyFn[T, R]) map[R][]T
- func Map[T any, R any](in []T, fn MapFn[T, R]) []R
- func MapToPtr[T any](in []T) []*T
- func MaxBy[T any, K cmp.Ordered](in []T, keyFn func(T) K) (T, bool)
- func MinBy[T any, K cmp.Ordered](in []T, keyFn func(T) K) (T, bool)
- func Partition[T any](in []T, matchFn MatchFn[T]) ([]T, []T)
- func Reject[T any](in []T, matchFn MatchFn[T]) []T
- func Scan[T any, A any](in []T, acc A, fn AccFn[T, A]) []A
- func SortBy[T any, K cmp.Ordered](in []T, keyFn func(T) K) []T
- func Take[T any](in []T, amount int) []T
- func TakeEvery[T any](in []T, n uint) []T
- func TakeWhile[T any](in []T, fn MatchFn[T]) []T
- func Unzip[A any, B any](in []Pair[A, B]) ([]A, []B)
- type AccFn
- type FlatMapFn
- type KeyFn
- type MapFn
- type MatchFn
- type Pair
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func All ¶
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 ¶
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
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
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
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
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
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 ¶
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 ¶
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 ¶
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
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
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
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
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
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
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 ¶
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 ¶
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 ¶
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
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 FlatMapFn ¶ added in v1.0.0
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 Pair ¶ added in v1.0.0
Pair holds two values of potentially different types.
func Zip ¶ added in v1.0.0
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