A collection of nice to have generic function and algorithms for slices, maps and channels
This project came about in the experimentation with go1.18 and generics with helper functions for slices. It now also includes
algorithms and constructs for dealing with channels and maps as well
It is expected to that there might be a lot of these types of libraries floating around after the release of go1.18.
The go team did not include any of these fairly common constructs in this release but instead put some of them into
the exp package. There for the might be quite a bit of overlap in the coming releases with this and other packages.
Some other work with similar concepts
- https://github.com/golang/exp/tree/master/slices
- https://github.com/golang/exp/tree/master/maps
- https://github.com/samber/lo
Install
go get github.com/modfin/henry/...
Usage
Import the part of henry you are interested of using
import ( "github.com/modfin/henry/chanz" "github.com/modfin/henry/mapz" "github.com/modfin/henry/slicez" )
Then use the functions in the libraries such as
pets := slicez.Sort([]string{"Dog", "Lizard", "Cat"}) // []string{"Cat", ,"Dog", "Lizard"}
Content
Henry contain tree main packages. slicez
, chanz
and mapz
Functions in slicez
- Clone
- Compact
- CompactFunc
- Compare
- CompareFunc
- Complement
- ComplementBy
- Concat
- Contains
- ContainsFunc
- Cut
- CutFunc
- Difference
- DifferenceBy
- Drop
- DropRight
- DropRightWhile
- DropWhile
- Each
- Equal
- EqualFunc
- Every
- EveryFunc
- Filter
- Find
- FindLast
- FlatMap
- Flatten
- Fold
- FoldRight
- GroupBy
- Head
- Index
- IndexFunc
- Intersection
- IntersectionBy
- Join
- KeyBy
- Last
- LastIndex
- LastIndexFunc
- Map
- Max
- Min
- None
- NoneFunc
- Nth
- Partition
- Reject
- Reverse
- Sample
- Search
- Shuffle
- Some
- SomeFunc
- Sort
- SortFunc
- Tail
- Take
- TakeRight
- TakeRightWhile
- TakeWhile
- Union
- UnionBy
- Uniq
- UniqBy
- Unzip
- Unzip2
- Zip
- Zip2
Functions in mapz
- Clear
- Clone
- Copy
- DeleteFunc
- DeleteValue
- Equal
- EqualFunc
- Keys
- Merge
- Remap
- Values
Functions in chanz
- Collect
- CollectUntil
- Compact
- Compact1
- CompactN
- CompactUntil
- Concat
- Concat1
- ConcatN
- ConcatUntil
- Drop
- Drop1
- DropAll
- DropN
- DropUntil
- DropWhile
- DropWhile1
- DropWhileN
- DropWhileUntil
- EveryDone
- FanOut
- FanOut1
- FanOutN
- FanOutUntil
- Filter
- Filter1
- FilterN
- FilterUntil
- Flatten
- Flatten1
- FlattenN
- FlattenUntil
- Generate
- Generate1
- GenerateN
- GenerateUntil
- Map
- Map1
- MapN
- MapUntil
- Merge
- Merge1
- MergeN
- MergeUntil
- Partition
- Partition1
- PartitionN
- PartitionUntil
- Peek
- Peek1
- PeekN
- PeekUntil
- Readers
- SomeDone
- Take
- Take1
- TakeN
- TakeUntil
- TakeWhile
- TakeWhile1
- TakeWhileN
- TakeWhileUntil
- Unzip
- Unzip1
- UnzipN
- UnzipUntil
- Writers
- Zip
- Zip1
- ZipN
- ZipUntil
Slicez
The slicez
package contains generic utility functions and algorithms for slices
Clone
Produces a copy of a given slice
s := []int{1,2,3} clone := slicez.Clone[int](s) // []int{1,2,3}
Compact
Removes consecutive duplicates from a slice
s := []int{1, 1, 2, 3, 3} slicez.Compact[int](s) // []int{1,2,3}
CompactFunc
Removes consecutive duplicates from a slice using a function for determine equality
s := []rune("Alot of white spaces") slicez.CompactFunc[rune](s, func(a, b rune) { return a == ' ' && a == b }) // "Alot of white spaces"
Compare
Compares two slices for equality
s1 := []int{1, 2, 3} s2 := []int{1, 2, 3} slicez.Compare[int](s1, s2) // 0
CompareFunc
Compares two slices for equality with supplied func
s1 := []int{1, 2, 3} s2 := []int{4, 5, 6} slicez.CompareFunc[int](s1, s2, func (a, b int) int{ return a%4 - b%4 }) // 0
Complement
Returns the complement of two slices
a := []int{1, 2, 3} b := []int{3, 2, 5, 5, 6, 1} slicez.Complement[int](a, b) // []int{5, 6}
ComplementBy
Concat
Concatenates slices into a new slice
a := []int{1, 2, 3} b := []int{4, 5, 6} b := []int{7, 8, 9} slicez.Concat[int](a, b, c) // []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
Contains
Return true if an element is present in the slice
slicez.Contains[int]([]int{1, 2, 3, 4, 5}, 3) // true
ContainsFunc
Returns true if the function returns true.
slicez.ContainsFunc[int]([]int{4, 5, 6, 7}, func(i int){ return i % 4 == 3 }) // true
Cut
Cuts a slice into two parts
slicez.Cut[int]([]int{1,2,3,4,5}, 3) // []int{1,2}, []int{4,5}, true
CutFunc
Cuts a slice into two parts
slicez.CutFunc[int]([]int{1,2,3,4,5}, func(i int){ return i == 3}) // []int{1,2}, []int{4,5}, true
Difference
Returns the difference between slices
a := []int{1,2,3} b := []int{2,3,4} c := []int{2,3,5} slicez.Difference[int](a, b, c) // []int{1,4,5}
DifferenceBy
Drop
Drops the first N elements
slicez.Drop[int]([]int{1, 2, 3, 4, 5}, 2) // []int{3,4,5}
DropRight
Drops the last N elements
slicez.DropRight[int]([]int{1, 2, 3, 4, 5}, 2) // []int{1,2,3}
DropWhile
Drops elements from the left until function returns false
slicez.DropWhile[int]([]int{1, 2, 3, 4, 5}, func (i int) {return i < 3}) // []int{3,4,5}
DropRightWhile
Drops elements from the right until function returns false
Applies a function to each element of a slice
slicez.Each[int]([]int{1, 2, 3}, func (i int) { fmt.Print(i) }) // 123
Equal
Returns true if two slices are identical
s1 := []int{1, 2, 3} s2 := []int{1, 2, 3} slicez.Equal[int](s1, s2) // true
EqualFunc
Returns true if two slices are identical, given an equality function
s1 := []int{1, 2, 3} s2 := []int{4, 5, 6} slicez.EqualFunc[int, int](s1, s2, func (a, b int) int{ return a%4 - b%4 }) // true
Every
Returns true if every element matches the given value
s1 := []int{1, 1, 1} slicez.Every[int](s1, 1) // true
EveryFunc
Every
Returns true if every element matches the given value using the equality function
s1 := []int{0, 3, 6} slicez.EveryFunc[int](s1, func (i int) { return i % 3 == 0}) // true
Filter
Filters a slice to contain things we are looking for
s1 := []int{1, 2, 3, 4} slicez.Filter[int](s1, func (i int) { return i % 2 == 0}) // []int{2,4}
Find
Find returns the first instance of an object where the function returns true
s1 := []int{1, 2, 3, 4, 5,6, 7} slicez.Find[int](s1, func (i int) { return i % 3 == 0}) // 3
FindLast
FindLast returns the last instance of an object where the function returns true
s1 := []int{1, 2, 3, 4, 5,6, 7} slicez.FindLast[int](s1, func (i int) { return i % 3 == 0}) // 6
FlatMap
Takes a slice, expands every element into a slice and flattens it to a single slice
s := []string{"a b c", "d e f"} slicez.FlatMap(s, func(e string) []string { return strings.Split(e, " ") }) // []string{"a","b","c","d","e","f"}
Flatten
Flattens a nested slice
s := [][]string{{"a", "b"}, {"c","d"}} slicez.Flatten(s) // []string{"a","b","c","d"}
Fold
Folds a slice into a value from the left (aka reduce)
// “>abcd””>
s := []string{"a", "b", "c","d"} slicez.Fold[string, string](s, func(acc string, str string) string { return acc + str}, ">") // ">abcd"
FoldRight
Folds a slice into a value from the right (aka reduce)
// “>dcba””>
s := []string{"a", "b", "c","d"} slicez.FoldRight[string, string](s, func(acc string, str string) string { return acc + str}, ">") // ">dcba"
GroupBy
Groups elements in a slice into a map
s = []int{0,1,2,3} slicez.GroupBy(s, func(e int) int {return i % 2}) // map[int][]int{0: [0,2], 1:[1,2]}
Head
Returns the first element of a slice if present
slicez.Head([]int{1,2,3}) // 1, nil
Index
Returns the index of the first occurrence of an element
slicez.Index([]int{1,2,3}, 2) // 1
IndexFunc
Returns the index of the first occurrence of an element using a function
slicez.IndexFunc([]int{1,2,3}, func(i int) bool {i % 2 == 1}) // 0
Intersection
Returns the intersection of slices
a := []int{1,2,3,4} b := []int{3,4,5,6} c := []int{3,4,8,9} slicez.Intersection(a,b,c) // []int{3,4}
IntersectionBy
Intersection
Returns the intersection of slices
a := []int{0,1} b := []int{4,2} c := []int{8,3} slicez.IntersectionBy(func(i int) int { return i % 4 } a,b,c) // []int{0,4,8}
Join
Joining a 2d slice into 1d slice using a glue
s = [][]string{{"hello", " ", "world"}, {"or", " ", "something"}} slicez.Join(s, []string{" "}) // []string{"hello", " ", "world", " ", "or", s" ", "something"}
KeyBy
Returns a map with the slice elements in it, using the by function to determine key
s = []int{1,2,3,4} slicez.KeyBy(s, func(i int) int { return i % 3 }) // map[int]int{0: 3, 1: 1, 2: 2}
Last
Returns the last element in a slice, or an error if len(s) == 0
slicez.Last([]int{1,2,3}) // 3, nil
LastIndex
Finds the last index of a needle, or -1 if not present
slicez.LastIndex([]int{1,1,2,1,3}, 1) // 3
LastIndexFunc
LastIndex
Finds the last index of a func needle, or -1 if not present
slicez.LastIndex([]int{1,2,3,4,5}, func(i int) bool { return i % 3 == 1}) // 2
Map
Map values in a slice producing a new one
s := []int{1,2,3} slicez.Map(s, func(i int) string { return fmt.Sprint(i)}) // []string{"1","2","3"}
Max
Returns the maximum value of a slice
s := []int{1,2,5,4} slicez.Max(s...) // 5
Min
Returns the minimum value of a slice
s := []int{1,2,5,0, 4} slicez.Min(s...) // 0
None
Returns true if no element match the needle
s := []int{1,2,3} slicez.None(s, 0) // true
NoneFunc
Returns true if no element returns true from the function
s := []int{1,2,3} slicez.NoneFunc(s, func(i int) bool { return i < 1 }) // true
Nth
Returns the N:th element in a slice, zero value if empty and regards the slice as a modulo group
s := []int{1,2,3} slicez.Nth(s, 1) // 2 slicez.Nth(s, 3) // 1 slicez.Nth(s, -1) // 3
Partition
Returns two slices which represents the partitions
s := []int{1,2,3,4} slicez.Partition(s, func(i int) bool { return i % 2 == 0}) // []int{2,4}, []int{1,3}
Reject
Reject is the complement to Filter and excludes items
s := []int{1,2,3,4} slicez.Reject(s, func(i int) bool { return i % 2 == 0}) // []int{1,3}
Reverse
Reverses a slice
s := []int{1,2,3} slicez.Reverse(s) //[]int{3,2,1}
Sample
Returns a random sample of size N from the slice
s := []int{1,2,3,4,5,6,7,8} slicez.Sample(s, 2) //[]int{8,3}
Search
Shuffle
Returns a shuffled version of the slice
s := []int{1,2,3,4,5} slicez.Shuffle(s) //[]int{3,1,4,5,3}
Some
Returns true there exist an element in the slice that is equal to the needle, an alias for Contains
s := []int{1,2,3,4,5} slicez.Some(s, 4) //true
SomeFunc
Returns true if there is an element in the slice for which the predicate function returns true
Sorts a slice
s := []int{3,2,1} slicez.Sort(s) //[]int{1,2,3}
SortFunc
Sorts a slice with a comparator
s := []int{1,2,3} slicez.SortFunc(s, func(a, b int) bool { return b < a }) //[]int{3,2,1}
Tail
Returns the tail of a slice
s := []int{1,2,3} slicez.Tail(s) // []int{2,3}
Take
Returns the N first element of a slice
s := []int{1,2,3,4} slicez.Take(s, 2) // []int{1,2}
TakeRight
Returns the N last element of a slice
s := []int{1,2,3,4} slicez.TakeRight(s, 2) // []int{3, 4}
TakeWhile
Returns the first element of a slice that as long as function returns t
s := []int{1,2,3,4} slicez.TakeRight(s, func(i int) bool { return i < 3}) // []int{1, 2}
TakeRightWhile
Returns the last element of a slice that as long as function returns t
Returs the union of a slices
a := []int{1,2,3} b := []int{3,4,5} slicez.Union(a, b) // []int{1,2,3,4,5}
UnionBy
Returs the union of a slices using a function for equality
a := []int{1,5} b := []int{2,4} slicez.UnionBy(func(i int) bool { return i % 2 == 0 } a, b) // []int{1,2}
Uniq
Returns a slice of uniq elements
a := []int{1,2,3,1,3,4} slicez.Uniq(a) // []int{1,2,3,4}
UniqBy
Returns a slice of uniq elements, where equality is determined through the function
a := []int{1,2,3,1,3,4} slicez.UniqBy(a, func(i int) bool { return i % 2 == 0 }) // []int{1,2}
Unzip
Takes a slice and unzips it into two slices
Takes a slice and unzips it into three slices
Takes 2 slices and zips them into one slice
a := []int{1,2,3} b := []string{"a","b","c"} slicez.Zip(a,b, func(i int, s string) string { return fmt.Sprint(i, s) }) // []string{"1a", "2b", "3c"}
Zip2
Takes 3 slices and zips them into one slice
a := []int{1,2,3} b := []string{"a","b","c"} b := []bool{true, false, true} slicez.Zip(a, b, c, func(i int, s string, b bool) string { return fmt.Sprint(b, i, s) }) // []string{"true1a", "false2b", "true3c"}
Mapz
The mapz
package contains generic utility functions and algorithms for maps
Clear
Deletes every entry in a map
m := map[int]int{1:1, 2:2} mapz.Clear(m) // map[int]int{}
Clone
Creates a clone of a map
m := map[int]int{1:1, 2:2} mapz.Clone(m) // map[int]int{1:1, 2:2}
Copy
Copies one map into another
src := map[int]int{1:1, 2:2} dst := map[int]int{1:0, 3:3} mapz.Copy(dst, src) // map[int]int{1:1, 2:2, 3:3}
DeleteFunc
Will remove all entries from a map where the del function returns true
m := map[int]int{1:1, 2:2, 3:3} mapz.DeleteFunc(m, func(k, v int) bool { return k == 2 }) // map[int]int{1:1, 3:3}
DeleteValue
Deletes a value and the associated key from a map
m := map[int]int{1:1, 2:800, 3:3} mapz.DeleteValue(m, 800) // map[int]int{1:1, 3:3}
Equal
Returns true if a map i equal
m1 := map[int]int{1:1, 3:3} m2 := map[int]int{1:1, 3:3} mapz.Equal(m1, m2) // true
EqualFunc
Returns true if a map i equal using the equality function to test it
m1 := map[int]int{1:1, 3:3} m2 := map[int]int{1:1, 3:6} map