collections

package module
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2023 License: MIT Imports: 5 Imported by: 0

README

version Go Reference commit stage Go Report Card codecov issues

Collections

Blazingly fast Collections package. Inspired by Laravel, written in Go.

Overview

go-collections offers a variety of methods and types to be used with slices and maps. Initially, its interface was based on Laravel Collections, but many more methods and functionalities will be added.

This package is still under development, there might be breaking changes introduced. Use with caution!

Pull requests are welcome. See Contributing

Generic functions

There are just functions with a slice type parameter to help the usage of slices. The main disadvantage here is the lack of piping.

func genericFunction() {
	Each(
		func(_, v int) {
			fmt.Println(v) // 2, 3, 4, 5
		},
		Map(
			func(_, v int) int {
				fmt.Println(v) // 1, 2, 3, 4
				return v + 1
			},
			[]int{1, 2, 3, 4},
		),
	)
}

Slice collection

Slice collection is a custom slice type with embedded methods. Most of the available methods here are just calls to the base generic functions, with the advantage of piping calls instead of nesting functions.

func sliceCollection() {
	Collect(1, 2, 3, 4).
		Map(func(_, v int) int {
			fmt.Println(v) // 1, 2, 3, 4
			return v + 1
		}).
		Each(func(_, v int) {
			fmt.Println(v) // 2, 3, 4, 5
		})
}

KV (map) collections

The KV collection is a bit more complex. It uses composed of two structs: the map, holding the keys and values, and a slice of keys, used to enable the collection to be ordered in any way needed by the user. This is important due to the lack of ordering on Go maps. The usage is similar to the Slice collection, with the ability to add comparable keys.

func mapCollection() {
	CollectMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4}).
		Sort(collections.Asc[int]()).
		Map(func(k string, v int) int {
			fmt.Printf("%s: %v\n", k, v) // a: 1, b: 2, c: 3, d: 4
			return v + 1
		}).
		Each(func(k string, v int) {
			fmt.Printf("%s: %v\n", k, v) // a: 2, b: 3, c: 4, d: 5
		})
}

Why?

Before type parameters (aka generics), Go lacked a way to do even trivial collection stuff without cumbersome boilerplate. After 1.18 was released, a myriad of possibilities was open. There are many available options right now, such as the awesome samber/lo. That said, none of the available options were what we (i.e. maintainers of this package) were looking for... So go-collection was born. The aim is to not only offer generic methods to be used with slices and maps but also offer custom types to manage collections in a pipeable fashion.

Major goals

The major goals for this package are:

  • offer a good, clear interface to interact with slices and maps
  • use no external dependencies
  • good resource usage without micro-optimizations - this is not intended to be used by real-time or performance critical applications

Limitations

Some of the methods available on the Laravel Collections are - by design - impossible to be implemented in Go. These methods were either adapted to be used in a way that made sense, or ignored completely.

Available types and methods

The complete reference of all types and their documentation is listed in their respective godoc. Below is a quick reference for each one of them.

Generic

Types

Functions

Slice collection

Most methods of the slice collection are just calls to the generic functions passing the collection as the slice argument and returning the result to allow piping. In addition, some methods are available:

Key/Value collection

Generic
Numeric

The numeric collection includes all methods from the generic kv collection and the additional methods listed bellow:

Performance

Despite the main description, this is not supposed to be a blazingly fast repository. Rather, it's intended to offer a good interface without deprecating performance. Benchmarks were made comparing the main methods to their respective raw versions using only the native data struct (e.g. slice or map). The full result will always be available as a build artifact of the respective release, but below is some of the main methods compared.

Benchmarks

TODO

Contributing

TODO

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Asc

func Asc[T internal.Relational]() func(T, T) bool

Asc can be used as a Sort param to order collections in ascending order. It only works on slices holding Relational values.

func Average

func Average[T internal.Number](slice []T) T

Average uses AverageE, omitting the error.

func AverageE

func AverageE[T internal.Number](slice []T) (T, error)

AverageE calculates the average value of the slice. Should the slice be empty, an instance of errors.EmptyCollectionError is returned.

func Chunk added in v0.1.0

func Chunk[V any](slice []V, size int) [][]V

Chunk breaks the slice into multiple, smaller slices of a given size

func Contains added in v0.0.4

func Contains[V any](slice []V, matcher Matcher[int, V]) bool

Contains checks if the slice holds at least one value matching the given matcher.

func Copy

func Copy[V any](slice []V) []V

Copy returns a copy of the input slice.

func Cut

func Cut[V any](slice *[]V, i int, optionalJ ...int) []V

Cut uses CutE, omitting the error.

func CutE

func CutE[V any](slice *[]V, i int, optionalJ ...int) ([]V, error)

CutE removes and returns the portion of the slice limited by i (included) and j (not included). Should either i or j be out of bounds, an instance of errors.IndexOutOfBounds is returned.

func DeleteE added in v0.0.4

func DeleteE[V any](slice *[]V, i int, optionalJ ...int) error

DeleteE deletes the element corresponding to i from the slice. Every element on the right of i will be re-indexed. Should either i be out of bounds, an instance of errors.IndexOutOfBounds is returned.

func Desc

func Desc[T internal.Relational]() func(T, T) bool

Desc can be used as a Sort param to order collections in descending order. It only works on slices holding Relational values.

func Diff added in v0.1.0

func Diff[V comparable](leftSlice, rightSlice []V) []V

Diff returns a slice containing the elements that appear in the Left slice but not in the Right slice.

func Duplicates added in v0.1.0

func Duplicates[V comparable](slice []V) []V

func Each

func Each[T any](f func(i int, v T), slice []T)

Each ia a typical for loop. The current index and values are passed to the closure on each iteration.

func First

func First[T any](slice []T) T

First calls FirstE, omitting the error.

func FirstE

func FirstE[T any](slice []T) (T, error)

FirstE simply calls GetE with the slice and 0 the target index.

func FirstWhere added in v0.0.4

func FirstWhere[V any](slice []V, matcher Matcher[int, V]) V

FirstWhere uses FirstWhereE, omitting the error.

func FirstWhereE added in v0.0.4

func FirstWhereE[V any](slice []V, matcher Matcher[int, V]) (V, error)

FirstWhereE returns the first value matched by the given matcher. Should no value match, an instance of errors.ValueNotFoundError is returned.

func FirstWhereField added in v0.0.4

func FirstWhereField[V any](slice []V, field string, matcher AnyMatcher) V

FirstWhereField uses FirstWhereFieldE, omitting the error.

func FirstWhereFieldE added in v0.0.4

func FirstWhereFieldE[V any](slice []V, field string, matcher AnyMatcher) (V, error)

FirstWhereFieldE uses FieldMatcher to match a struct field from elements present on S. Should either no element match, the field doesn't exist on the struct V, or V is not a struct, an instance of errors.ValueNotFoundError is returned.

func ForPage added in v0.1.0

func ForPage[V any](slice []V, page, size int) []V

ForPage returns a slice containing the items that would be present on a given page number

func ForgetE added in v0.0.4

func ForgetE[V any](slice *[]V, i int, optionalJ ...int) error

ForgetE is an alias to DeleteE.

func Get

func Get[T any](slice []T, i int) T

Get calls GetE, omitting the error.

func GetE

func GetE[T any](slice []T, i int) (T, error)

GetE indexes the slice with i, returning the corresponding value when it exists. Should i be negative or greater then the slice's len, a zeroed T value and an errors.ValueNotFound error is returned. This function is safe to be used with empty slices.

func GroupBy added in v0.1.0

func GroupBy[V any, T comparable](slice []V, f func(v V) T) map[T][]V

GroupBy groups the slice's items by the return value of `f`

func Interpose added in v0.1.0

func Interpose[V any](slice []V, sep V) []V

Interpose adds `sep` between every element in `slice`

func Intersect added in v0.1.0

func Intersect[V comparable](leftSlice, rightSlice []V) []V

Intersect creates a new slice containing the elements present in both left and right slices. The given slices are left untouched.

func KeyBy added in v0.1.0

func KeyBy[V any, K comparable](slice []V, f func(v V) K) map[K]V

KeyBy keys the collection by the given key If multiple items have the same key, the last one will appear in the new collection

func Last

func Last[T any](slice []T) T

Last uses LastE, omitting the error.

func LastBy added in v0.1.0

func LastBy[T any](slice []T, matcher Matcher[int, T]) T

LastBy uses LastByE, omitting the error.

func LastByE added in v0.1.0

func LastByE[T any](slice []T, matcher Matcher[int, T]) (T, error)

LastByE returns the last matched element in the slice.

func LastE

func LastE[T any](slice []T) (T, error)

LastE simply calls GetE with the slice and len-1 as the target index.

func Map

func Map[T any, R any](slice []T, f func(i int, v T) R) []R

Map applies f to each element of the slice and builds a new slice with f's returned value. The built slice is returned. The mapped slice has the same order as the input slice.

func Max

func Max[T internal.Number](slice []T) T

Max uses MaxE, omitting the error.

func MaxE

func MaxE[T internal.Number](slice []T) (T, error)

MaxE returns the maximum value stored on the numeric slice. Should the slice be empty, an error is returned.

func Median

func Median[T internal.Number](slice []T) float64

Median calculates and returns the median value of the slice.

func Min

func Min[T internal.Number](slice []T) T

Min uses MinE, omitting the error.

func MinE

func MinE[T internal.Number](slice []T) (T, error)

MinE returns the minimal value stored on the numeric slice. Should the slice be empty, an error is returned.

func Mode added in v0.0.4

func Mode[T comparable](slice []T) []T

Mode returns the values that appear most often in the slice. Order is not guaranteed.

func Nth added in v0.1.0

func Nth[V any, N internal.Integer](slice []V, n N) []V

Nth creates a new slice consisting of every n-th element, starting at 0.

func NthOffset added in v0.1.0

func NthOffset[V any, N internal.Integer](slice []V, n N, off N) []V

NthOffset creates a new slice consisting of every n-th element, starting at the given offset.

func Pad added in v0.1.0

func Pad[V any](slice []V, size int, pad V) []V

Pad will fill the slice with `pad` to the specified `size`. To pad to the left, specify a negative `size`. No padding will take place if the absolute value of `size` is less than or equal to the length of `slice`

func PadLeft added in v0.1.0

func PadLeft[V any](slice []V, size int, pad V) []V

PadLeft will fill the slice with `pad` from the left to the specified `size`. No padding will take place if the `size` is less than or equal to the length of `slice`

func PadRight added in v0.1.0

func PadRight[V any](slice []V, size int, pad V) []V

PadRight will fill the slice with `pad` to the specified `size`. No padding will take place if the `size` is less than or equal to the length of `slice`

func Partition added in v0.1.0

func Partition[V any](slice []V, predicate func(v V) bool) ([]V, []V)

Partition divides the slice into two slices based on the given predicate function. It returns a slice of elements that satisfy the predicate and a slice of elements that do not.

func Pop

func Pop[T any](slice *[]T) T

Pop uses PopE, omitting the error.

func PopE

func PopE[T any](slice *[]T) (T, error)

PopE takes the last element of the slice, deletes and returns it.

func Prepend added in v0.1.0

func Prepend[V any](slice []V, value V) []V

Prepend adds `value` to the beginning of `slice`

func Push

func Push[T any](slice []T, v T) []T

Push appends v to the slice.

func Put

func Put[T any](slice []T, i int, v T) []T

Put sets the position i in the slice with v. Should i be greater than the slice, a new slice with capacity to store v at i index is allocated. Put preserves the original values, shifting the slice so the new value can be stored without affecting the previous values.

func Random added in v0.1.0

func Random[V any](slice []V) V

Random uses RandomE, omitting the error.

func RandomE added in v0.1.0

func RandomE[V any](slice []V) (V, error)

RandomE returns a random item from `slice` and errors if `slice` is empty.

func Range added in v0.1.0

func Range[T internal.Integer](min, max T) []T

Range returns a slice containing integers in the specified range (i.e. [min, max])

func Reduce added in v0.1.0

func Reduce[T, V any](slice []T, f func(carry V, v T, i int) V, carry V) V

Reduce reduces the collection to a single value, passing the result of each iteration into the subsequent iteration

func Reverse added in v0.1.0

func Reverse[V any](slice []V) []V

Reverse reverses the given slice

func Search[T any](v T, slice []T) int

Search uses SearchE, omitting the error.

func SearchE

func SearchE[T any](slice []T, v T) (int, error)

SearchE searches for v in the slice. The evaluation is done using reflect.DeepEqual. Should the value be found, it's index is returned. Otherwise, T's zeroed value and an instance of errors.ValueNotFoundError is returned.

func Shift added in v0.0.3

func Shift[T any](slice *[]T) T

Shift uses ShiftE, omitting the error.

func ShiftE added in v0.0.3

func ShiftE[T any](slice *[]T) (T, error)

ShiftE (aka pop front) is equivalent to PopE, but deletes and returns the first slice element.

func Shuffle added in v0.1.0

func Shuffle[V any](slice []V) []V

Shuffle pseudo-randomizes the order of elements.

func Skip added in v0.1.0

func Skip[V any](slice []V, skip int) []V

Skip returns `slice` with `skip` elements removed from the beginning

func SkipUntil added in v0.1.0

func SkipUntil[V any](slice []V, matcher Matcher[int, V]) []V

SkipUntil skips over items from `slice` until `matcher` returns true and then returns the remaining items in the slice

func SkipWhile added in v0.1.0

func SkipWhile[V any](slice []V, matcher Matcher[int, V]) []V

SkipWhile skips over items from `slice` while `matcher` returns true and then returns the remaining items in the slice

func Sliding added in v0.1.0

func Sliding[V any](slice []V, window int) [][]V

Sliding returns a "sliding window" view of the items in `slice`

func SlidingStep added in v0.1.0

func SlidingStep[V any](slice []V, window, step int) [][]V

SlidingStep returns a "sliding window" view of the items in `slice`. Each window will by `step` items apart

func Sort

func Sort[T any](slice []T, f func(current, next T) bool)

Sort sorts the slice based on f. It can be used used with Asc or Desc functions or with a custom closure.

func SortBy added in v0.1.0

func SortBy[T any, S internal.Relational](slice []T, f func(t T) S) []T

SortBy sorts `slice` based on `f`.

func SortByDesc added in v0.1.0

func SortByDesc[T any, S internal.Relational](slice []T, f func(t T) S) []T

SortByDesc sorts desc `slice` based on f.

func Splice added in v0.1.0

func Splice[V any](slice []V, idx int) ([]V, []V)

Splice returns a slice of items starting at the specified index, and the updated slice with the items removed.

func SpliceN added in v0.1.0

func SpliceN[V any](slice []V, idx, size int) ([]V, []V)

SpliceN returns a slice of `slice` starting at the `index` with length `size`, and the updated slice with the items removed.

func Split added in v0.1.0

func Split[V any](slice []V, numberOfGroups int) [][]V

Split breaks `slice` into the given number of groups

func Sum

func Sum[T internal.Number](slice []T) T

Sum sums all the values stored on the numeric slice and returns the result.

func SumBy added in v0.1.0

func SumBy[V any, T internal.Number](slice []V, f func(v V) T) T

SumBy accumulates values returned by `f`

func Take added in v0.1.0

func Take[V any](slice []V, n int) []V

Take returns a slice with the specified number of items from `slice`. You may also pass a negative integer to take the specified number of items from the end of the `slice`.

func TakeUntil added in v0.3.0

func TakeUntil[V any](slice []V, matcher Matcher[int, V]) []V

TakeUntil returns items in the `slice` until `matcher` returns true

func TakeWhile added in v0.2.0

func TakeWhile[V any](slice []V, matcher Matcher[int, V]) []V

TakeWhile returns items in the `slice` until `matcher` returns false

func Tally added in v0.0.4

func Tally[T comparable](slice []T) map[T]int

Tally counts the occurrence of each element on the slice.

func Times added in v0.4.0

func Times[V any](n int, f func(i int) V) []V

Times creates a new slice by invoking `f` `n` times:

func Unique added in v0.1.0

func Unique[V comparable](slice []V) []V

Unique returns all distinct items in the slice

func UniqueBy added in v0.1.0

func UniqueBy[V any, T comparable](slice []V, f func(v V) T) []V

UniqueBy uses the returned value of `f` to return distinct values in `slice`

func Zip added in v0.1.0

func Zip[V any](slices ...[]V) [][]V

Zip merges the values of the given slices at their corresponding indexes

Types

type AnyMatcher added in v0.1.0

type AnyMatcher = Matcher[any, any]

AnyMatcher is used by matchers on functions that must compare keys and values from a collection. It is used as a functional option. To learn more, see: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis

func And added in v0.0.4

func And[V any](matchers ...AnyMatcher) AnyMatcher

And combines all the given matchers into a single matcher which returns true when all matchers return true.

func FieldEquals added in v0.0.4

func FieldEquals[V any](field string, value any) AnyMatcher

FieldEquals uses FieldMatch composed with ValueEquals as the matcher.

func FieldMatch added in v0.0.4

func FieldMatch[V any](field string, matcher AnyMatcher) AnyMatcher

FieldMatch will attempt to retrieve the value corresponding to the given struct field name. V must be a struct, otherwise calls to the matcher will always return false. The retrieved value will be used to supply the given matcher.

func KeyEquals

func KeyEquals(key any) AnyMatcher

KeyEquals builds a matcher to compare the given key to the key passed by the matcher caller.

func ValueCastGT added in v0.5.0

func ValueCastGT[T internal.Number](value T) AnyMatcher

ValueCastGT acts just like ValueGT, but using AnyMatcher and performing a cast on the collection value.

func ValueCastLT added in v0.5.0

func ValueCastLT[T internal.Number](value T) AnyMatcher

ValueCastLT acts just like ValueGT, but using AnyMatcher and performing a cast on the collection value.

func ValueDiffers

func ValueDiffers(value any) AnyMatcher

ValueDiffers builds a matcher to compare the given value (with reflect.DeepEqual) to the value passed by the matcher caller. It has the opposite behavior from ValueEquals

type Matcher

type Matcher[K any, V any] func(key K, value V) bool

func AndValue added in v0.0.4

func AndValue[K any, V any](v V, matchers ...func(V) Matcher[K, V]) Matcher[K, V]

AndValue is similar to And, but it receives matchers wrapped by a function which will receive v. It is useful to compare build matchers dynamically at the execution time rather than at the function's call time (i.e. the composed matchers won't be called until the higher order matcher is called).

func Not added in v0.1.0

func Not[K any, V any](matcher Matcher[K, V]) Matcher[K, V]

Not inverts the result of `matcher`

func Or added in v0.0.4

func Or[K any, V any](matchers ...Matcher[K, V]) Matcher[K, V]

Or combines all the given matchers into a single matcher which returns true when at least one of the given matcher returns true.

func OrValue added in v0.0.4

func OrValue[K any, V any](v V, matchers ...func(V) Matcher[K, V]) Matcher[K, V]

OrValue is similar to Or, but it receives matchers wrapped by a function which will receive v. It is useful to compare build matchers dynamically at the execution time rather than at the function's call time (i.e. the composed matchers won't be called until the higher order matcher is called).

func ValueDeepEquals added in v0.5.0

func ValueDeepEquals[K any, V any](value V) Matcher[K, V]

ValueDeepEquals builds a matcher to compare the given value (with reflect.DeepEqual) to the value passed by the matcher caller.

func ValueEquals

func ValueEquals[K any, V comparable](value V) Matcher[K, V]

ValueEquals builds a matcher to compare the given value (with ==) to the value passed by the matcher caller.

func ValueGT added in v0.0.4

func ValueGT[K any, V internal.Relational](value V) Matcher[K, V]

ValueGT compares the given numeric value to check if it is greater than the value given by the matcher's caller.

func ValueLT added in v0.0.4

func ValueLT[K any, V internal.Relational](value V) Matcher[K, V]

ValueLT compares the given numeric value to check if it is lesser than the value given by the matcher's caller.

Directories

Path Synopsis
Package errors holds custom errors common to all collections types.
Package errors holds custom errors common to all collections types.
kv
Package kv provides a custom map collection type, functions and methods related to maps.
Package kv provides a custom map collection type, functions and methods related to maps.
Package slice provides a custom slice collection type, functions and methods related to slices.
Package slice provides a custom slice collection type, functions and methods related to slices.
tests

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL