Gollections
slice, map, iter.Seq, iter.Seq2 APIs for transforming, filtering, reducing, summing and other iteration-based tasks.
Install / Use
/learn @m4gshm/GollectionsREADME
Gollections
Gollections is set of functions for slices, maps, iter.Seq, iter.Seq2 and additional implementations of data structures such as ordered map or set aimed to reduce boilerplate code.
Supports Go version 1.24.
For example, it’s need to group some users by their role names converted to lowercase:
var users = []User{
{name: "Bob", age: 26, roles: []Role{{"Admin"}, {"manager"}}},
{name: "Alice", age: 35, roles: []Role{{"Manager"}}},
{name: "Tom", age: 18},
}
You can make clear code, extensive, but without dependencies:
var namesByRole = map[string][]string{}
add := func(role string, u User) {
namesByRole[role] = append(namesByRole[role], u.Name())
}
for _, u := range users {
if roles := u.Roles(); len(roles) == 0 {
add("", u)
} else {
for _, r := range roles {
add(strings.ToLower(r.Name()), u)
}
}
}
//map[:[Tom] admin:[Bob] manager:[Bob Alice]]
Or you can write more compact code using the collections API, like:
import (
"github.com/m4gshm/gollections/slice/convert"
"github.com/m4gshm/gollections/slice/group"
)
var namesByRole = group.ByMultipleKeys(users, func(u User) []string {
return convert.AndConvert(u.Roles(), Role.Name, strings.ToLower)
}, User.Name)
// map[:[Tom] admin:[Bob] manager:[Bob Alice]]
Installation
go get -u github.com/m4gshm/gollections
Slices
data, err := slice.Conv(slice.Of("1", "2", "3", "4", "_", "6"), strconv.Atoi)
//[1 2 3 4], invalid syntax
even := func(i int) bool { return i%2 == 0 }
result := slice.Reduce(slice.Convert(slice.Filter(data, even), strconv.Itoa), op.Sum) //"24"
In the example is used only small set of slice functions as slice.Filter, slice.Conv slice.Convert, and slice.Reduce. More you can look in the slice package.
Shortcut packages
result := sum.Of(filter.AndConvert(data, even, strconv.Itoa))
This is a shorter version of the previous example that used short aliases sum.Of and filter.AndConvert. More shortcuts you can find by exploring slices subpackages.
Be careful when use several slice functions subsequently like
slice.Filter(slice.Convert(…)). This can lead to unnecessary RAM
consumption. Consider seq instead of slice API.
Main slice functions
Instantiators
slice.Of
var s = slice.Of(1, 3, -1, 2, 0) //[]int{1, 3, -1, 2, 0}
range_.Of
import "github.com/m4gshm/gollections/slice/range_"
var increasing = range_.Of(-1, 3) //[]int{-1, 0, 1, 2}
var decreasing = range_.Of('e', 'a') //[]rune{'e', 'd', 'c', 'b'}
var nothing = range_.Of(1, 1) //nil
range_.Closed
var increasing = range_.Closed(-1, 3) //[]int{-1, 0, 1, 2, 3}
var decreasing = range_.Closed('e', 'a') //[]rune{'e', 'd', 'c', 'b', 'a'}
var one = range_.Closed(1, 1) //[]int{1}
Sorters
sort.Asc, sort.Desc
// sorting in-place API
import "github.com/m4gshm/gollections/slice/sort"
var ascendingSorted = sort.Asc([]int{1, 3, -1, 2, 0}) //[]int{-1, 0, 1, 2, 3}
var descendingSorted = sort.Desc([]int{1, 3, -1, 2, 0}) //[]int{3, 2, 1, 0, -1}
sort.By, sort.ByDesc
// sorting copied slice API does not change the original slice
import "github.com/m4gshm/gollections/slice/clone/sort"
// see the User structure above
var users = []User{
{name: "Bob", age: 26},
{name: "Alice", age: 35},
{name: "Tom", age: 18},
{name: "Chris", age: 41},
}
var byName = sort.By(users, User.Name)
//[{Alice 35 []} {Bob 26 []} {Chris 41 []} {Tom 18 []}]
var byAgeReverse = sort.DescBy(users, User.Age)
//[{Chris 41 []} {Alice 35 []} {Bob 26 []} {Tom 18 []}]
Collectors
group.Of
import (
"github.com/m4gshm/gollections/convert/as"
"github.com/m4gshm/gollections/expr/use"
"github.com/m4gshm/gollections/slice/group"
)
var ageGroups map[string][]User = group.Of(users, func(u User) string {
return use.If(u.age <= 20, "<=20").If(u.age <= 30, "<=30").Else(">30")
}, as.Is)
//map[<=20:[{Tom 18 []}] <=30:[{Bob 26 []}] >30:[{Alice 35 []} {Chris 41 []}]]
group.Order
import (
"github.com/m4gshm/gollections/convert/as"
"github.com/m4gshm/gollections/expr/use"
"github.com/m4gshm/gollections/slice/group"
)
var order, ageGroups = group.Order(users, func(u User) string {
return use.If(u.age <= 20, "<=20").If(u.age <= 30, "<=30").Else(">30")
}, as.Is)
//order [<=30 >30 <=20]
//ageGroups map[<=20:[{Tom 18 []}] <=30:[{Bob 26 []}] >30:[{Alice 35 []} {Chris 41 []}]]
group.ByMultipleKeys
import (
"github.com/m4gshm/gollections/slice/convert"
"github.com/m4gshm/gollections/slice/group"
)
var namesByRole = group.ByMultipleKeys(users, func(u User) []string {
return convert.AndConvert(u.Roles(), Role.Name, strings.ToLower)
}, User.Name)
// map[:[Tom] admin:[Bob] manager:[Bob Alice]]
slice.Map, slice.AppendMap
import "github.com/m4gshm/gollections/slice"
var agePerGroup map[string]int = slice.Map(users, User.Name, User.Age)
//"map[Alice:35 Bob:26 Chris:41 Tom:18]"
slice.MapOrder, slice.AppendMapOrder
import "github.com/m4gshm/gollections/slice"
var names, agePerName = slice.MapOrder(users, User.Name, User.Age)
//"[Bob Alice Tom Chris]"
//"map[Alice:35 Bob:26 Chris:41 Tom:18]"
slice.MapResolv, slice.AppendMapResolv
import (
"github.com/m4gshm/gollections/map_/resolv"
"github.com/m4gshm/gollections/op"
"github.com/m4gshm/gollections/slice"
)
var ageGroupedSortedNames map[string][]string
ageGroupedSortedNames = slice.MapResolv(users, func(u User) string {
return op.IfElse(u.age <= 30, "<=30", ">30")
}, User.Name, resolv.SortedSlice)
//map[<=30:[Bob Tom] >30:[Alice Chris]]
Reducers
sum.Of
import "github.com/m4gshm/gollections/op/sum"
var sum = sum.Of(1, 2, 3, 4, 5, 6) //21
slice.Reduce
var sum = slice.Reduce([]int{1, 2, 3, 4, 5, 6}, func(i1, i2 int) int { return i1 + i2 })
//21
slice.Accum
import (
"github.com/m4gshm/gollections/op"
"github.com/m4gshm/gollections/slice"
)
var sum = slice.Accum(100, slice.Of(1, 2, 3, 4, 5, 6), op.Sum)
//121
slice.First
import (
"github.com/m4gshm/gollections/predicate/more"
"github.com/m4gshm/gollections/slice"
)
result, ok := slice.First([]int{1, 3, 5, 7, 9, 11}, more.Than(5)) //7, true
slice.Head
import (
"github.com/m4gshm/gollections/slice"
)
result, ok := slice.Head([]int{1, 3, 5, 7, 9, 11}) //1, true
slice.Top
import (
"github.com/m4gshm/gollections/slice"
)
result := slice.Top(3, []int{1, 3, 5, 7, 9, 11}) //[]int{1, 3, 5}
slice.Last
import (
"github.com/m4gshm/gollections/predicate/less"
"github.com/m4gshm/gollections/slice"
)
result, ok := slice.Last([]int{1, 3, 5, 7, 9, 11}, less.Than(9)) //7, true
slice.Tail
import (
"github.com/m4gshm/gollections/slice"
)
result, ok := slice.Tail([]int{1, 3, 5, 7, 9, 11}) //11, true
Element converters
slice.Convert
var s []string = slice.Convert([]int{1, 3, 5, 7, 9, 11}, strconv.Itoa)
//[]string{"1", "3", "5", "7", "9", "11"}
slice.Conv
result, err := slice.Conv(slice.Of("1", "3", "5", "_7", "9", "11"), strconv.Atoi)
//[]int{1, 3, 5}, ErrSyntax
Slice converters
slice.Filter
import (
"github.com/m4gshm/gollections/predicate/exclude"
"github.com/m4gshm/gollections/predicate/one"
"github.com/m4gshm/gollections/slice"
)
var f1 = slice.Filter([]int{1, 3, 5, 7, 9, 11}, one.Of(1, 7).Or(one.Of(11))) //[]int{1, 7, 11}
var f2 = slice.Filter([]int{1, 3, 5, 7, 9, 11}, exclude.All(1, 7, 11)) //[]int{3, 5, 9}
slice.Flat
import (
"github.com/m4gshm/gollections/convert/as"
"github.com/m4gshm/gollections/slice"
)
var i []int = slice.Flat([][]int{{1, 2, 3}, {4}, {5, 6}}, as.Is)
//[]int{1, 2, 3, 4, 5, 6}
Operations chain functions
-
convert.AndReduce, conv.AndReduce
-
convert.AndFilter
-
filter.AndConvert
These functions combine converters, filters and reducers.
Maps
Main map functions
Instantiators
clone.Of
import "github.com/m4gshm/gollections/map_/clone"
var bob = map[string]string{"name": "Bob"}
var tom = map[string]string{"name": "Tom"}
var employers = map[string]map[string]string{
"devops": bob,
"jun": tom,
}
copy := clone.Of(employers)
delete(copy, "jun")
bob["name"] = "Superbob"
fmt.Printf("%v\n", employers) //map[devops:map[name:Superbob] jun:map[name:Tom]]
fmt.Printf("%v\n", copy) //map[devops:map[name:Superbob]]
clone.Deep
import "github.com/m4gshm/gollections/map_/clone"
var bob = map[string]string{"name": "Bob"}
var tom = map[string]string{"name": "Tom"}
var employers = map[string]map[string]string{
"devops": bob,
"jun": tom,
}
copy := clone.Deep(employers, func(employer map[string]string) map[string]string {
return clone.Of(employer)
})
delete(copy, "jun")
bob["name"] = "Superbob"
fmt.Printf("%v\n", employers) //map[devops:map[name:Superbob] jun:map[name:Tom]]
fmt.Printf("%v\n", copy) //map[devops:map[name:Bob]]
Collectors
map_.Slice
var users = map_.Slice(employers, func(title string, employer map[string]string) User {
return User{name: employer["name"], roles: []Role{{name: title}}}
})
//[{name:Bob age:0 roles:[{name:devops}]} {name:Tom age:0 roles:[{name:jun}]}]
map_.Keys, map_.Values, map_.KeysConvert, map_.ValuesConvert
var employers
