Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/sxyazi/go-collection
Useful collection functions for golang, based on generic types.
https://github.com/sxyazi/go-collection
collection generic-types go-collection golang golang-collection
Last synced: 5 days ago
JSON representation
Useful collection functions for golang, based on generic types.
- Host: GitHub
- URL: https://github.com/sxyazi/go-collection
- Owner: sxyazi
- License: mit
- Created: 2022-02-04T11:36:42.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2022-07-21T00:49:40.000Z (over 2 years ago)
- Last Synced: 2024-10-31T17:13:47.791Z (12 days ago)
- Topics: collection, generic-types, go-collection, golang, golang-collection
- Language: Go
- Homepage: https://pkg.go.dev/github.com/sxyazi/[email protected]
- Size: 141 KB
- Stars: 40
- Watchers: 3
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# go-collection
English | [简体中文](README_zh-CN.md)
`go-collection` provides developers with a convenient set of functions for working with common slices, maps, and arrays data. These functions are based on the generic types of Go 1.18, which makes it easier to use them without annoying type assertions. In addition to using these functions directly, it also supports method chaining.
```go
collect.Reduce(collect.Filter(collect.Map([]int{1, 2, 3}, fn), fn), fn)
```Equivalent to:
```go
collect.UseSlice([]int{1, 2, 3}).Map(fn).Filter(fn).Reduce(fn)
```## Installation
```shell
go get -u github.com/sxyazi/go-collection
```Then import it
```go
import collect "github.com/sxyazi/go-collection"
```## API
Its API is very simple and if you have used other similar packages, you should be able to get started with it in a few minutes. **For convenience, they are described below in function form**.
### Slice
The corresponding chained function is `collect.UseSlice()`
- `Len` gets the length of the slice
Examples```go
d1 := []int{1, 2, 3}
collect.Len(d1) // 3d2 := []string{"a", "b", "c"}
collect.Len(d2) // 3
```
- `Each` iterates over each element in the slice
Examples```go
d := []float64{1, 2, 3}
collect.Each(d, func(value float64, index int) {
fmt.Println(index, value)
})
```
- `Empty` checks if the slice is empty
Examples```go
var d []int
collect.Empty(d) // true
```
- `Same` checks if the contents of two slices are the same
Examples```go
d1 := []int{1, 2, 3}
d2 := []int{1, 2, 3}
collect.Same(d1, d2) // trued3 := [][]int{{1, 2, 3}, {4, 5, 6}}
d4 := [][]int{{1, 2, 3}, {4, 5, 6}}
collect.Same(d3, d4) // true
```
- `First` gets the first element of the slice
Examples```go
d1 := []int{1, 2, 3}
value, ok := collect.First(d1) // 1, truevar d2 []int
value, ok = collect.First(d2) // 0, false
```
- `Last` gets the last element of the slice
Examples```go
d1 := []int{1, 2, 3}
value, ok := collect.Last(d1) // 3, truevar d2 []int
value, ok = collect.Last(d2) // 0, false
```
- `Index` gets the index of the specified element in the slice, and returns -1 if it does not exist.
Examples```go
d1 := []int{1, 2, 3}
collect.Index(d1, 2) // 1s1 := []string{"a", "b", "c"}
s2 := []string{"d", "e", "f"}
collect.Index([][]string{s1, s2}, s2) // 1
```
- `Contains` checks if the slice contains the specified element
Examples```go
d1 := []int{1, 2, 3}
collect.Contains(d1, 2) // trues1 := []string{"a", "b", "c"}
s2 := []string{"d", "e", "f"}
collect.Contains([][]string{s1, s2}, s2) // true
```
- `Diff` computes the difference set of two slices
Examples```go
d := []int{1, 2, 3}
collect.Diff(d, []int{2, 3}) // []int{1}
```
- `Filter` filters the elements in the slice
Examples```go
collect.Filter([]int{1, 2, 3, 4, 5}, func(value, index int) bool {
return value % 2 == 0
}) // []int{2, 4}
```
- `Map` iterates over and sets the value of the elements in the slice
Examples```go
collect.Map([]int{1, 2, 3}, func(value, index int) int {
return value * 2
}) // []int{2, 4, 6}
```
- `Unique` removes duplicate elements in the slice
Examples```go
d := []int{1, 2, 3, 3, 4}
collect.Unique(d) // []int{1, 2, 3, 4}
```
- `Duplicates` gets the duplicate elements in the slice
Examples```go
d := []string{"a", "b", "a", "c"}
collect.Duplicates(d) // map[int]string{2: "a"}
```
- `Merge` merges the current slice with other slices
Examples```go
d1 := []int{1, 2}
d2 := []int{3, 4}
d3 := []int{5, 6}collect.Merge(d1, d2) // []int{1, 2, 3, 4}
collect.Merge(d1, d2, d3) // []int{1, 2, 3, 4, 5, 6}
```
- `Random` gets an element of the slice at random
Examples```go
d := []int{1, 2}
value, ok := collect.Random(d) // 1 or 2, trued := []int{}
value, ok := collect.Random(d) // 0, false
```
- `Reverse` reverses the elements in a slice
Examples```go
d := []int{1, 2}
collect.Reverse(d) // []int{2, 1}
```
- `Shuffle` randomly shuffles the elements in a slice
Examples```go
d := []int{1, 2}
collect.Shuffle(d) // []int{1, 2} or []int{2, 1}
```
- `Slice` takes a segment from a slice
ExamplesFunction signature: `Slice(items T, offset int)`
```go
d := []int{1, 2, 3, 4, 5}
collect.Slice(d, 2) // []int{3, 4, 5}
collect.Slice(d, -1) // []int{5}
collect.Slice(d, -2) // []int{4, 5}
```Function signature: `Slice(items T, offset, length int)`
```go
d := []int{1, 2, 3, 4, 5}
collect.Slice(d, 0, 2) // []int{1, 2}
collect.Slice(d, 2, 3) // []int{3, 4, 5}
collect.Slice(d, 3, -2) // []int{3, 4}
collect.Slice(d, -4, 3) // []int{2, 3, 4}
```
- `Split` splits a slice into multiple slices by the specified amount
Examples```go
d := []int{1, 2, 3, 4, 5}
collect.Split(d, 2) // [][]int{{1, 2}, {3, 4}, {5}}
```
- `Splice` removes a segment from the slice
ExamplesFunction signature: `Splice(items T, offset int)`
```go
d := []int{1, 2, 3, 4, 5}
collect.Splice(&d, 2) // []int{3, 4, 5}
d // []int{1, 2}
```Function signature: `Splice(items T, offset, length int)`
```go
d := []int{1, 2, 3, 4, 5}
collect.Splice(&d, 2, 2) // []int{3, 4}
d // []int{1, 2, 5}
```Function signature: `Splice(items T, offset, length int, replacements ...T|E)`
```go
d1 := []int{1, 2, 3, 4}
collect.Splice(&d1, 1, 2, []int{22, 33}) // []int{2, 3}
d1 // []int{1, 22, 33, 4}d2 := []int{1, 2, 3, 4}
collect.Splice(&d2, 1, 2, 22, 33) // []int{2, 3}
d2 // []int{1, 22, 33, 4}d3 := []int{1, 2, 3, 4}
collect.Splice(&d3, 1, 2, []int{22}, 33, []int{55}) // []int{2, 3}
d3 // []int{1, 22, 33, 55, 4}
```It is worth noting that this method also supports the use of negative numbers as arguments, and its behavior is the same as that of `Slice`, which is not repeated here due to space constraints.
- `Reduce` reduces the collection to a single value, and the parameters of each iteration are the results of the previous iteration
Examples```go
collect.Reduce([]int{1, 2, 3}, 100, func(carry, value, key int) int {
return carry + value
}) // 106
```
- `Pop` removes and returns the last element of the collection
Examples```go
d := []int{1, 2}
v, ok := collect.Pop(&d) // 2, true
d // []int{1}c := collect.UseSlice([]int{1, 2})
v, ok := c.Pop() // 2, true
c.All() // []int{1}
```
- `Push` appends an element to the end of a collection
Examples```go
d := []int{1, 2}
Push(&d, 3)
d // []int{1, 2, 3}collect.UseSlice([]int{1, 2}).Push(3).All() // []int{1, 2, 3}
```
- `Where` filters the collection by the specified rules
ExamplesFunction signature: `Where(items T, target any)`
```go
collect.Where([]int{1, 2, 3}, 2) // []int{2}
```Function signature: `Where(items T, operator string, target any)`
```go
d := []int{1, 2, 3, 4}
collect.Where(d, "=", 2) // []int{2}
collect.Where(d, "!=", 2) // []int{1, 3, 4}
collect.Where(d, ">", 2) // []int{3, 4}
collect.Where(d, ">=", 2) // []int{2, 3, 4}
collect.Where(d, "<", 3) // []int{1, 2}
collect.Where(d, "<=", 3) // []int{1, 2, 3}
```Function signature: `Where(items T, key any, target any)`
```go
d := []User{{ID: 1, Name: "Hugo"}, {ID: 2, Name: "Lisa"}, {ID: 3, Name: "Iris"}, {ID: 4, Name: "Lisa"}}
collect.Where(d, "Name", "Lisa") // []User{{2 Lisa} {4 Lisa}}
```Function signature: `Where(items T, key any, operator string, target any)`
```go
d := []User{{ID: 1, Name: "Hugo"}, {ID: 2, Name: "Lisa"}, {ID: 3, Name: "Iris"}, {ID: 4, Name: "Lisa"}}
collect.Where(d, "Name", "!=", "Lisa") // []User{{1 Hugo} {3 Iris}}
```
- `WhereIn` removes elements from the collection that do not exist in the specified slice
ExamplesFunction signature: `WhereIn(items T, targets []any)`
```go
d := []int{1, 2, 3, 4}
collect.WhereIn(d, []int{2, 3}) // []int{2, 3}
```Function signature: `WhereIn(items T, key any, targets []any)`
```go
d := []User{{ID: 1, Name: "Hugo"}, {ID: 2, Name: "Lisa"}, {ID: 3, Name: "Iris"}, {ID: 4, Name: "Lisa"}}
collect.WhereIn(d, "Name", []string{"Hugo", "Iris"}) // []User{{1 Hugo} {3 Iris}}
```
- `WhereNotIn` removes elements from the collection that exist in the specified slice
ExamplesFunction signature: `WhereNotIn(items T, targets []any)`
```go
d := []int{1, 2, 3, 4}
collect.WhereNotIn(d, []int{2, 3}) // []int{1, 4}
```Function signature: `WhereNotIn(items T, key any, targets []any)`
```go
d := []User{{ID: 1, Name: "Hugo"}, {ID: 2, Name: "Lisa"}, {ID: 3, Name: "Iris"}, {ID: 4, Name: "Lisa"}}
collect.WhereNotIn(d, "Name", []string{"Lisa", "Iris"}) // []User{{1 Hugo}}
```
### Array
Exactly the same as [slice](#Slice), you just pass in the array converted to a slice:
```go
arr := [3]int{1, 2, 3}collect.Len(arr[:])
// or
collect.UseSlice(arr[:]).Len()
```### Map
The corresponding chained function is `collect.UseMap()`
- `Len` gets the number of elements in the map
Examples```go
d1 := map[string]int{"a": 1, "b": 2, "c": 3}
collect.Len(d1) // 3
```
- `Empty` checks if the map is empty
Examples```go
var d map[string]int
collect.Empty(d) // true
```
- `Only` gets the elements of the map with the specified keys
Examples```go
d := map[string]int{"a": 1, "b": 2, "c": 3}
collect.Only(d, "a") // map[string]int{"a": 1}
collect.Only(d, "a", "b") // map[string]int{"a": 1, "b": 2}
```
- `Except` gets the elements of the map with the specified keys removed
Examples```go
d := map[string]int{"a": 1, "b": 2, "c": 3}
collect.Except(d, "a") // map[string]int{"b": 2, "c": 3}
collect.Except(d, "a", "b") // map[string]int{"c": 3}
```
- `Keys` gets all the keys in the map
Examples```go
d := map[string]int{"a": 1, "b": 2, "c": 3}
collect.Keys(d) // []string{"a", "b", "c"}
```
- `DiffKeys` compares with the given collection and returns the key/value pairs in the given collection that do not exist in the original collection
Examples```go
d1 := map[string]int{"a": 1, "b": 2, "c": 3}
d2 := map[string]int{"b": 22, "c": 33}collect.DiffKeys(d1, d2) // map[string]int{"a": 1}
```
- `Has` checks if the map contains the specified key
Examples```go
d := map[string]int{"a": 1}
collect.Has(d, "a") // true
```
- `Get` gets the value of the specified key in the map
Examples```go
d := map[string]int{"a": 1}value, ok := collect.Get(d, "a") // 1, true
value, ok := collect.Get(d, "b") // 0, false
```
- `Put` sets the value of the specified key in the map
Examples```go
d := map[string]int{"a": 1}
collect.Put(d, "b", 2) // map[string]int{"a": 1, "b": 2}
```
- `Pull` removes the specified key from the collection and returns its value
Examples```go
d := map[string]int{"a": 1, "b": 2}
v, ok := collect.Pull(d, "b") // 2, true
d // map[string]int{"a": 1}
```
- `Merge` merges the current map with other maps
Examples```go
d1 := map[string]int{"a": 1, "b": 2}
d2 := map[string]int{"b": 22}
d3 := map[string]int{"b": 222, "c": 3}collect.MapMerge(d1, d2) // map[string]int{"a": 1, "b": 22}
collect.UseMap(d1).Merge(d2).All() // Equal to the abovecollect.MapMerge(d1, d2, d3) // map[string]int{"a": 1, "b": 222, "c": 3}
collect.UseMap(d1).Merge(d2, d3).All() // Equal to the above
```
- `Union` unites the current map with other maps, and the items in the original map are given priority
Examples```go
d1 := map[string]int{"a": 1, "b": 2}
d2 := map[string]int{"b": 22, "c": 3}
collect.Union(d1, d2) // map[string]int{"a": 1, "b": 2, "c": 3}
```
### Number slice
The corresponding chained function is `collect.UseNumber()`,which is a subset of [slice](#Slice) and includes, in addition to all the methods of slice, the additional:
- `Sum` calculates the sum
Examples```go
collect.Sum([]float64{1, 3.14}) // 4.14
```
- `Min` calculates the minimum value
Examples```go
collect.Min([]int{0, 1, -3}) // -3
```
- `Max` calculates the maximum value
Examples```go
collect.Max([]int{0, 1, -3}) // 1
```
- `Sort` sorts the numbers in the collection in ascending order
Examples```go
collect.Sort([]float64{1, -4, 0, -4.3}) // []float64{-4.3, -4, 0, 1}
```
- `SortDesc` sorts the numbers in the collection in descending order
Examples```go
collect.SortDesc([]float64{1, -4, 0, -4.3}) // []float64{1, 0, -4, -4.3}
```
- `Avg` calculates the average
Examples```go
collect.Avg([]int{1, 2, 3, 4}) // 2.5
```
- `Median` calculates the median
Examples```go
collect.Median([]int{1, 2, 3, 4}) // 2.5
```
### Standalone functions
Due to Golang's support for generics, it is [not possible to define generic types in methods](https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#no-parameterized-methods), so only their function implementations (which do not support chain calls) are listed below:
- `AnyGet` gets value of arbitrary types (slices, maps, arrays, structures, and pointers to these) in a non-strict form
Examples```go
m := map[string]int{"a": 1, "b": 2}
collect.AnyGet[int](m, "b") // 2u := &User{"Email": "[email protected]"}
collect.AnyGet[string](u, "Email") // [email protected]s := [][]int{{1, 2}, {3, 4}}
collect.AnyGet[[]int](s, 1) // []{3, 4}
```
- `Pluck` retrieves all values for a given key. supports all values supported by `AnyGet`
Examples```go
d := []User{{ID: 33, Name: "Lucy"}, {ID: 193, Name: "Peter"}}
collect.Pluck[int](d, "ID") // int[]{33, 193}
```
- `MapPluck` retrieves all values of a given key, only maps are supported
Examples```go
d := []map[string]int{{"ID": 33, "Score": 10}, {"ID": 193, "Score": 6}}
collect.MapPluck(d, "ID") // int[]{33, 193}
```
- `KeyBy` retrieves a collection with the value of the given key as the identifier (if there are duplicate keys, only the last one will be kept). Supports all values supported by `AnyGet`
Examples```go
d := []User{{ID: 33, Name: "Lucy"}, {ID: 193, Name: "Peter"}, {ID: 194, Name: "Peter"}}
collect.KeyBy[string](d, "Name") // map[Lucy:{33 Lucy} Peter:{194 Peter}]
```
- `MapKeyBy` retrieves the collection with the value of the given key as the identifier (if there are duplicate keys, only the last one will be kept), only maps are supported
Examples```go
d := []map[string]int{{"ID": 33, "Score": 6}, {"ID": 193, "Score": 10}, {"ID": 194, "Score": 10}}
collect.MapKeyBy(d, "Score") // map[6:map[ID:33 Score:6] 10:map[ID:194 Score:10]]
```
- `GroupBy` groups the items in a collection using the value of the given key as the identifier. Supports all values supported by `AnyGet`
Examples```go
d := []User{{ID: 33, Name: "Lucy"}, {ID: 193, Name: "Peter"}, {ID: 194, Name: "Peter"}}
collect.GroupBy[string](d, "Name") // map[Lucy:[{33 Lucy}] Peter:[{193 Peter} {194 Peter}]]
```
- `MapGroupBy` groups items in a collection using the value of the given key as the identifier, only maps are supported
Examples```go
d := []map[string]int{{"ID": 33, "Score": 6}, {"ID": 193, "Score": 10}, {"ID": 194, "Score": 10}}
collect.MapGroupBy(d, "Score") // map[6:[map[ID:33 Score:6]] 10:[map[ID:193 Score:10] map[ID:194 Score:10]]]
```
- `Count` counts the number of occurrences of each element in the slice
Examples```go
d := []bool{true, true, false}
collect.Count(d) // map[bool]int{true: 2, false: 1}
```
- `Times` creates a new collection of slice by calling the callback with specified number of times
Examples```go
collect.Times(3, func(number int) float64 {
return float64(number) * 3.14
}) // *SliceCollection{[]float64{3.14, 6.28, 9.42}}
```
- `SortBy` calls a callback for each element and performs an ascending sort by the return value of the callback
Examples```go
collect.SortBy([]int{2, 1, 3}, func(item, index int) string {
return strconv.Itoa(item)
}) // *SliceCollection{[]int{1, 2, 3}}
```
- `SortByDesc` calls a callback for each element and performs a descending sort by the return value of the callback
Examples```go
collect.SortByDesc([]int{2, 1, 3}, func(item, index int) string {
return strconv.Itoa(item)
}) // *SliceCollection{[]int{3, 2, 1}}
```
## License
go-collection is [MIT licensed](LICENSE).