Skip to content

sxyazi/go-collection

Repository files navigation

go-collection

English | 简体中文

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.

collect.Reduce(collect.Filter(collect.Map([]int{1, 2, 3}, fn), fn), fn)

Equivalent to:

collect.UseSlice([]int{1, 2, 3}).Map(fn).Filter(fn).Reduce(fn)

Installation

go get -u github.com/sxyazi/go-collection

Then import it

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
    d1 := []int{1, 2, 3}
    collect.Len(d1) // 3
    
    d2 := []string{"a", "b", "c"}
    collect.Len(d2) // 3
  • Each iterates over each element in the slice

    Examples
    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
    var d []int
    collect.Empty(d) // true
  • Same checks if the contents of two slices are the same

    Examples
    d1 := []int{1, 2, 3}
    d2 := []int{1, 2, 3}
    collect.Same(d1, d2) // true
    
    d3 := [][]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
    d1 := []int{1, 2, 3}
    value, ok := collect.First(d1) // 1, true
    
    var d2 []int
    value, ok = collect.First(d2) // 0, false
  • Last gets the last element of the slice

    Examples
    d1 := []int{1, 2, 3}
    value, ok := collect.Last(d1) // 3, true
    
    var 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
    d1 := []int{1, 2, 3}
    collect.Index(d1, 2) // 1
    
    s1 := []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
    d1 := []int{1, 2, 3}
    collect.Contains(d1, 2) // true
    
    s1 := []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
    d := []int{1, 2, 3}
    collect.Diff(d, []int{2, 3})  // []int{1}
  • Filter filters the elements in the slice

    Examples
    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
    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
    d := []int{1, 2, 3, 3, 4}
    collect.Unique(d)  // []int{1, 2, 3, 4}
  • Duplicates gets the duplicate elements in the slice

    Examples
    d := []string{"a", "b", "a", "c"}
    collect.Duplicates(d)  // map[int]string{2: "a"}
  • Merge merges the current slice with other slices

    Examples
    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
    d := []int{1, 2}
    value, ok := collect.Random(d)  // 1 or 2, true
    
    d := []int{}
    value, ok := collect.Random(d)  // 0, false
  • Reverse reverses the elements in a slice

    Examples
    d := []int{1, 2}
    collect.Reverse(d)  // []int{2, 1}
  • Shuffle randomly shuffles the elements in a slice

    Examples
    d := []int{1, 2}
    collect.Shuffle(d)  // []int{1, 2} or []int{2, 1}
  • Slice takes a segment from a slice

    Examples

    Function signature: Slice(items T, offset int)

    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)

    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
    d := []int{1, 2, 3, 4, 5}
    collect.Split(d, 2)  // [][]int{{1, 2}, {3, 4}, {5}}
  • Splice removes a segment from the slice

    Examples

    Function signature: Splice(items T, offset int)

    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)

    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)

    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
    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
    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
    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

    Examples

    Function signature: Where(items T, target any)

    collect.Where([]int{1, 2, 3}, 2)  // []int{2}

    Function signature: Where(items T, operator string, target any)

    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)

    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)

    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

    Examples

    Function signature: WhereIn(items T, targets []any)

    d := []int{1, 2, 3, 4}
    collect.WhereIn(d, []int{2, 3})  // []int{2, 3}

    Function signature: WhereIn(items T, key any, targets []any)

    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

    Examples

    Function signature: WhereNotIn(items T, targets []any)

    d := []int{1, 2, 3, 4}
    collect.WhereNotIn(d, []int{2, 3})  // []int{1, 4}

    Function signature: WhereNotIn(items T, key any, targets []any)

    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, you just pass in the array converted to a slice:

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
    d1 := map[string]int{"a": 1, "b": 2, "c": 3}
    collect.Len(d1) // 3
  • Empty checks if the map is empty

    Examples
    var d map[string]int
    collect.Empty(d) // true
  • Only gets the elements of the map with the specified keys

    Examples
    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
    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
    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
    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
    d := map[string]int{"a": 1}
    collect.Has(d, "a")  // true
  • Get gets the value of the specified key in the map

    Examples
    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
    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
    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
    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 above
    
    collect.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
    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 and includes, in addition to all the methods of slice, the additional:

  • Sum calculates the sum

    Examples
    collect.Sum([]float64{1, 3.14})  // 4.14
  • Min calculates the minimum value

    Examples
    collect.Min([]int{0, 1, -3})  // -3
  • Max calculates the maximum value

    Examples
    collect.Max([]int{0, 1, -3})  // 1
  • Sort sorts the numbers in the collection in ascending order

    Examples
    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
    collect.SortDesc([]float64{1, -4, 0, -4.3})  // []float64{1, 0, -4, -4.3}
  • Avg calculates the average

    Examples
    collect.Avg([]int{1, 2, 3, 4})  // 2.5
  • Median calculates the median

    Examples
    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, 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
    m := map[string]int{"a": 1, "b": 2}
    collect.AnyGet[int](m, "b")  // 2
    
    u := &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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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.