gogu
CategoryData Structures and Algorithms
SubcategoryMiscellaneous Data Structures and Algorithms
Stars109
A comprehensive, reusable and efficient concurrent-safe generics utility functions and data structures library
About gogu
This large README is shown as a plain-text preview. Read the full README at the source
# gogu (Go Generics Utility)

[](https://goreportcard.com/report/github.com/esimov/gogu)
[](https://github.com/esimov/gogu/actions/workflows/ci.yml)
[](https://pkg.go.dev/github.com/esimov/gogu)
[](https://github.com/esimov/gogu/releases/tag/v1.0.3)
[](./LICENSE)
**Gogu** is a versatile, comprehensive, reusable and efficient concurrent-safe utility functions and data structures library taking advantage of the Go generics. It was inspired by other well known and established frameworks like [lodash](https://lodash.com/) or [Apache Commons](https://commons.apache.org/) and some concepts being more closer to the functional programming paradigms.
Its main purpose is to facilitate the ease of working with common data structures like slices, maps and strings, through the implementation of many utility functions commonly used in the day-by-day jobs, but also integrating some of the most used data structure algorithms.
## ✨ Features
**In what's different this library from other Go libraries exploring Go generics?**
- [x] It's concurrent-safe (with the exception of B-tree package)
- [x] Implements a dozens of time related functions like: [`before`](<#func-before>), [`after`](<#func-after>), [`delay`](<#func-delay>), [`memoize`](<#func-memoizert-v-memoize>), [`debounce`](<#func-newdebounce>), [`once`](<#func-once>), [`retry`](<#func-rtypet-retry>)
- [x] Rich utility functions to operate with strings
- [x] Very wide range of supported functions to deal with slice and map operations
- [x] Extensive test coverage
- [x] Implements the most used data structures
- [x] Thourough documentation accompanied with examples
## 🚀 Run
```bash
$ go get github.com/esimov/gogu
```
## 🛠 Usage
```go
package main
import "github.com/esimov/gogu"
func main() {
// main program
}
```
## 📖 Specifications
- **Generic Data Structures**
- [`bst`](https://github.com/esimov/gogu/tree/master/bstree): Binary Search Tree data structure implementation, where each node has at most two child nodes and the key of its internal node is greater than all the keys in the respective node's left subtree and less than the ones in the right subtree
- [`btree`](https://github.com/esimov/gogu/tree/master/btree): B-tree data structure implementation which is a self-balancing tree data structure maintaining its values in sorted order
- [`cache`](https://github.com/esimov/gogu/tree/master/cache): a basic in-memory key-value storage system
- [`heap`](https://github.com/esimov/gogu/tree/master/heap): Binary Heap data structure implementation where each node of the subtree is greather or equal then the parent node
- [`list`](https://github.com/esimov/gogu/tree/master/list): implements a singly and doubly linked list data structure
- [`queue`](https://github.com/esimov/gogu/tree/master/queue): package queue implements a FIFO (First-In-First-Out) data structure in two forms: using as storage system a resizing array and a doubly linked list
- [`stack`](https://github.com/esimov/gogu/tree/master/stack): package stack implements a LIFO (Last-In-First-Out) data structure where the last element added to the stack is processed first
- [`trie`](https://github.com/esimov/gogu/tree/master/trie): package trie provides a thread safe implementation of the ternary search tree data structure. Tries are used for locating specific keys from within a set or for quick lookup searches within a text like auto-completion or spell checking.
- **General utility functions**
- [Abs](<#func-abs>)
- [Clamp](<#func-clamp>)
- [Compare](<#func-compare>)
- [Equal](<#func-equal>)
- [InRange](<#func-inrange>)
- [Invert](<#func-invert>)
- [Less](<#func-less>)
- [Max](<#func-max>)
- [Min](<#func-min>)
- **Strings utility functions**
- [CamelCase](<#func-camelcase>)
- [Capitalize](<#func-capitalize>)
- [KebabCase](<#func-kebabcase>)
- [N](<#func-n>)
- [Null](<#func-null>)
- [NumToString](<#func-numtostring>)
- [Pad](<#func-pad>)
- [PadLeft](<#func-padleft>)
- [PadRight](<#func-padright>)
- [ReverseStr](<#func-reversestr>)
- [SnakeCase](<#func-snakecase>)
- [SplitAtIndex](<#func-splitatindex>)
- [Substr](<#func-substr>)
- [ToLower](<#func-tolower>)
- [ToUpper](<#func-toupper>)
- [Unwrap](<#func-unwrap>)
- [Wrap](<#func-wrap>)
- [WrapAllRune](<#func-wrapallrune>)
- **Slice utility functions**
- [Chunk](<#func-chunk>)
- [SumBy](#sumby)
- [Contains](<#func-contains>)
- [Difference](<#func-difference>)
- [DifferenceBy](<#func-differenceby>)
- [Drop](<#func-drop>)
- [DropWhile](<#func-dropwhile>)
- [DropRightWhile](<#func-droprightwhile>)
- [Duplicate](<#func-duplicate>)
- [DuplicateWithIndex](<#func-duplicatewithindex>)
- [Every](<#func-every>)
- [Filter](<#func-filter>)
- [FindAll](<#func-findall>)
- [FindIndex](<#func-findindex>)
- [FindLastIndex](<#func-findlastindex>)
- [FindMax](<#func-findmax>)
- [FindMaxBy](<#func-findmaxby>)
- [FindMaxByKey](<#func-findmaxbykey>)
- [FindMin](<#func-findmin>)
- [FindMinBy](<#func-findminby>)
- [FindMinByKey](<#func-findminbykey>)
- [Flatten](<#func-flatten>)
- [ForEach](<#func-foreach>)
- [ForEachRight](<#func-foreachright>)
- [GroupBy](<#func-groupby>)
- [IndexOf](<#func-indexof>)
- [Intersection](<#func-intersection>)
- [IntersectionBy](<#func-intersectionby>)
- [LastIndexOf](<#func-lastindexof>)
- [Mean](<#func-mean>)
- [Merge](<#func-merge>)
- [Nth](<#func-nth>)
- [Partition](<#func-partition>)
- [PartitionMap](<#func-partitionmap>)
- [Pluck](<#func-pluck>)
- [Range](<#func-range>)
- [RangeRight](<#func-rangeright>)
- [Reduce](<#func-reduce>)
- [Reject](<#func-reject>)
- [Reverse](<#func-reverse>)
- [Shuffle](<#func-shuffle>)
- [SliceToMap](<#func-slicetomap>)
- [Some](<#func-some>)
- [Sum](<#func-sum>)
- [SumBy](<#func-sumby>)
- [ToSlice](<#func-toslice>)
- [Union](<#func-union>)
- [Unique](<#func-unique>)
- [UniqueBy](<#func-uniqueby>)
- [Unzip](<#func-unzip>)
- [Without](<#func-without>)
- [Zip](<#func-zip>)
- **Map utility functions**
- [Filter2DMapCollection](<#func-filter2dmapcollection>)
- [FilterMap](<#func-filtermap>)
- [FilterMapCollection](<#func-filtermapcollection>)
- [Find](<#func-find>)
- [FindByKey](<#func-findbykey>)
- [FindKey](<#func-findkey>)
- [Keys](<#func-keys>)
- [Map](<#func-map>)
- [MapCollection](<#func-mapcollection>)
- [MapContains](<#func-mapcontains>)
- [MapEvery) bool](<#func-mapevery>)
- [MapKeys](<#func-mapkeys>)
- [MapSome](<#func-mapsome>)
- [MapUnique](<#func-mapunique>)
- [MapValues](<#func-mapvalues>)
- [Omit](<#func-omit>)
- [OmitBy](<#func-omitby>)
- [Pick](<#func-pick>)
- [PickBy](<#func-pickby>)
- [Values](<#func-values>)
- **Concurrency and time related utility functions**
- [After](<#func-after>)
- [Before](<#func-before>)
- [Delay](<#func-delay>)
- [Flip](<#func-flip>)
- [Memoize](<#func-memoizert-v-memoize>)
- [NewDebounce](<#func-newdebounce>)
- [Once](<#func-once>)
- [Retry](<#func-rtypet-retry>)
- [RetryWithDelay](<#func-rtypet-retrywithdelay>)
## func Abs
## func [Abs](<https://github.com/esimov/gogu/blob/master/math.go#L30>)
```go
func Abs[T Number](x T) T
```
Abs returns the absolut value of x.
## func [After](<https://github.com/esimov/gogu/blob/master/func.go#L29>)
```go
func After[V constraints.Signed](n *V, fn func())
```
After creates a function wrapper that does nothing at first. From the nth call onwards, it starts actually invoking the callback function. Useful for grouping responses, where you need to be sure that all the calls have finished just before proceeding to the actual job.
<details><summary>Example</summary>
<p>
```go
{
sample := []int{1, 2, 3, 4, 5, 6}
length := len(sample) - 1
initVal := 0
fn := func(val int) int {
return val + 1
}
ForEach(sample, func(val int) {
now := time.Now()
After(&length, func() {
<-time.After(10 * time.Millisecond)
initVal = fn(initVal)
after := time.Since(now).Milliseconds()
fmt.Println(after)
})
})
}
```
#### Output
```
10
```
</p>
</details>
## func [Before](<https://github.com/esimov/gogu/blob/master/func.go#L39>)
```go
func Before[S ~string, T any, V constraints.Signed](n *V, c *cache.Cache[S, T], fn func() T) T
```
Before creates a function wrapper that memoizes its return value. From the nth call onwards, the memoized result of the last invocation is returned immediately instead of invoking function again. So the wrapper will invoke function at most n\-1 times.
<details><summary>Example</summary>
<p>
```go
{
c := cache.New[string, int](cache.DefaultExpiration, cache.NoExpiration)
var n = 3
sample := []int{1, 2, 3}
ForEach(sample, func(val int) {
fn := func() int {
<-time.After(10 * time.Millisecond)
return n
}
res := Before(&n, c, fn)
// The trick to test this function is to decrease the n value after each iteration.
// We can be sure that the callback function is not served from the cache if n > 0.
// In this case the cache item "func" should be empty.
if n > 0 {
val, _ := c.Get("func")
fmt.Println(val)
fmt.Println(res)
}
if n <= 0 {
// Here the callback function is served from the cache.
val, _ := c.Get("func")
fmt.Println(val)
fmt.Println(res)
}
})
}
```
#### Output
```
<nil>
2
<nil>
1
&{0 0}
0
```
</p>
</details>
## func [CamelCase](<https://github.com/esimov/gogu/blob/master/string.go#L96>)
```go
func CamelCase[T ~string](str T) T
```
CamelCase converts a string to camelCase \(https://en.wikipedia.org/wiki/CamelCase\).
<details><summary>Example</summary>
<p>
```go
{
fmt.Println(CamelCase("Foo Bar"))
fmt.Println(CamelCase("--foo-Bar--"))
fmt.Println(CamelCase("__foo-_Bar__"))
fmt.Println(CamelCase("__FOO BAR__"))
fmt.Println(CamelCase(" FOO BAR "))
fmt.Println(CamelCase("&FOO&baR "))
fmt.Println(CamelCase("&&foo&&bar__"))
}
```
#### Output
```
fooBar
fooBar
fooBar
fooBar
fooBar
fooBar
fooBar
```
</p>
</details>
## func [Capitalize](<https://github.com/esimov/gogu/blob/master/string.go#L81>)
```go
func Capitalize[T ~string](str T) T
```
Capitalize converts the first letter of the string to uppercase and the remaining letters to lowercase.
## func [Chunk](<https://github.com/esimov/gogu/blob/master/slice.go#L405>)
```go
func Chunk[T comparable](slice []T, size int) [][]T
```
Chunk split the slice into groups of slices each having the length of size. In case the source slice cannot be distributed equally, the last slice will contain fewer elements.
<details><summary>Example</summary>
<p>
```go
{
fmt.Println(Chunk([]int{0, 1, 2, 3}, 2))
fmt.Println(Chunk([]int{0, 1, 2, 3, 4}, 2))
fmt.Println(Chunk([]int{0, 1}, 1))
}
```
#### Output
```
[[0 1] [2 3]]
[[0 1] [2 3] [4]]
[[0] [1]]
```
</p>
</details>
## func [Clamp](<https://github.com/esimov/gogu/blob/master/math.go#L38>)
```go
func Clamp[T Number](num, min, max T) T
```
Clamp returns a range\-limited number between min and max.
## func [Compare](<https://github.com/esimov/gogu/blob/master/generic.go#L11>)
```go
func Compare[T comparable](a, b T, comp CompFn[T]) int
```
Compare compares two values using as comparator the callback function argument.
<details><summary>Example</summary>
<p>
```go
{
res1 := Compare(1, 2, func(a, b int) bool {
return a < b
})
fmt.Println(res1)
res2 := Compare("a", "b", func(a, b string) bool {
return a > b
})
fmt.Println(res2)
}
```
#### Output
```
1
-1
```
</p>
</details>
## func [Contains](<https://github.com/esimov/gogu/blob/master/slice.go#L172>)
```go
func Contains[T comparable](slice []T, value T) bool
```
Contains returns true if the value is present in the collection.
## func [Delay](<https://github.com/esimov/gogu/blob/master/func.go#L20>)
```go
func Delay(delay time.Duration, fn func()) *time.Timer
```
Delay invokes the callback function with a predefined delay.
<details><summary>Example</summary>
<p>
```go
{
ch := make(chan struct{})
now := time.Now()
var value uint32
timer := Delay(20*time.Millisecond, func() {
atomic.AddUint32(&value, 1)
ch <- struct{}{}
})
r1 := atomic.LoadUint32(&value)
fmt.Println(r1)
<-ch
if timer.Stop() {
<-timer.C
}
r1 = atomic.LoadUint32(&value)
fmt.Println(r1)
after := time.Since(now).Milliseconds()
fmt.Println(after)
}
```
#### Output
```
0
1
20
```
</p>
</details>
## func [Difference](<https://github.com/esimov/gogu/blob/master/slice.go#L363>)
```go
func Difference[T comparable](s1, s2 []T) []T
```
Difference is similar to Without, but returns the values from the first slice that are not present in the second slice.
## func [DifferenceBy](<https://github.com/esimov/gogu/blob/master/slice.go#L384>)
```go
func DifferenceBy[T comparable](s1, s2 []T, fn func(T) T) []T
```
DifferenceBy is like Difference, except that invokes a callback function on each element of the slice, applying the criteria by which the difference is computed.
## func [Drop](<https://github.com/esimov/gogu/blob/master/slice.go#L425>)
```go
func Drop[T any](slice []T, n int) []T
```
Drop creates a new slice with n elements dropped from the beginning. If n \< 0 the elements will be dropped from the back of the collection.
## func [DropWhile](<https://github.com/esimov/gogu/blob/master/slice.go#L438>)
```go
func DropWhile[T any](slice []T, fn func(T) bool) []T
```
DropWhile creates a new slice excluding the elements dropped from the beginning. Elements are dropped by applying the condition invoked in the callback function.
<details><summary>Example</summary>
<p>
```go
{
res := DropWhile([]string{"a", "aa", "bbb", "ccc"}, func(elem string) bool {
return len(elem) > 2
})
fmt.Println(res)
}
```
#### Output
```
[a aa]
```
</p>
</details>
## func [DropRightWhile](<https://github.com/esimov/gogu/blob/master/slice.go#L452>)
```go
func DropRightWhile[T any](slice []T, fn func(T) bool) []T
```
DropRightWhile creates a new slice excluding the elements dropped from the end. Elements are dropped by applying the condition invoked in the callback function.
## func [Duplicate](<https://github.com/esimov/gogu/blob/master/slice.go#L182>)
```go
func Duplicate[T comparable](slice []T) []T
```
Duplicate returns the duplicated values of a collection.
<details><summary>Example</summary>
<p>
```go
{
input := []int{-1, -1, 0, 1, 2, 3, 2, 5, 1, 6}
fmt.Println(Duplicate(input))
}
```
#### Output
```
[-1 1 2]
```
</p>
</details>
## func [DuplicateWithIndex](<https://github.com/esimov/gogu/blob/master/slice.go#L206>)
```go
func DuplicateWithIndex[T comparable](slice []T) map[T]int
```
DuplicateWithIndex puts the duplicated values of a collection into a map as a key value pair, where the key is the collection element and the value is its position.
<details><summary>Example</summary>
<p>
```go
{
input := []int{-1, -1, 0, 1, 2, 3, 2, 5, 1, 6}
fmt.Println(DuplicateWithIndex(input))
}
```
#### Output
```
map[-1:0 1:3 2:4]
```
</p>
</details>
## func [Equal](<https://github.com/esimov/gogu/blob/master/generic.go#L21>)
```go
func Equal[T comparable](a, b T) bool
```
Equal checks if two values are equal.
## func [Every](<https://github.com/esimov/gogu/blob/master/slice.go#L136>)
```go
func Every[T any](slice []T, fn func(T) bool) bool
```
Every returns true if all the elements of a slice satisfies the criteria of the callback function.
## func [Filter](<https://github.com/esimov/gogu/blob/master/filter.go#L4>)
```go
func Filter[T any](slice []T, fn func(T) bool) []T
```
Filter returns all the elements from the collection which satisfies the conditional logic of the callback function.
<details><summary>Example</summary>
<p>
```go
{
input := []int{1, 2, 3, 4, 5, 10, 20, 30, 40, 50}
res := Filter(input, func(val int) bool {
return val >= 10
})
fmt.Println(res)
}
```
#### Output
```
[10 20 30 40 50]
```
</p>
</details>
## func [Filter2DMapCollection](<https://github.com/esimov/gogu/blob/master/filter.go#L63>)
```go
func Filter2DMapCollection[K comparable, V any](collection []map[K]map[K]V, fn func(map[K]V) bool) []map[K]map[K]V
```
Filter2DMapCollection filter out a two\-dimensional collection of map items by applying the conditional logic of the callback function.
## func [FilterMap](<https://github.com/esimov/gogu/blob/master/filter.go#L33>)
```go
func FilterMap[K comparable, V any](m map[K]V, fn func(V) bool) map[K]V
```
FilterMap iterates over the elements of a collection and returns a new collection representing all the items which satisfies the criteria formulated in the callback function.
<details><summary>Example</summary>
<p>
```go
{
input := map[int]string{1: "John", 2: "Doe", 3: "Fred"}
res := FilterMap(input, func(v string) bool {
return v == "John"
})
fmt.Println(res)
}
```
#### Output
```
map[1:John]
```
</p>
</details>
## func [FilterMapCollection](<https://github.com/esimov/gogu/blob/master/filter.go#L47>)
```go
func FilterMapCollection[K comparable, V any](collection []map[K]V, fn func(V) bool) []map[K]V
```
FilterMapCollection filter out a one dimensional collection of map items by applying the conditional logic of the callback function.
<details><summary>Example</summary>
<p>
```go
{
input := []map[string]int{
{"bernie": 22},
{"robert": 30},
}
res := FilterMapCollection(input, func(val int) bool {
return val > 22
})
fmt.Println(res)
}
```
#### Output
```
[map[robert:30]]
```
</p>
</details>
## func [Find](<https://github.com/esimov/gogu/blob/master/map.go#L128>)
```go
func Find[K constraints.Ordered, V any](m map[K]V, fn func(V) bool) map[K]V
```
Find iterates over the elements of a map and returns the first item for which the callback function returns true.
## func [FindAll](<https://github.com/esimov/gogu/blob/master/find.go#L33>)
```go
func FindAll[T any](s []T, fn func(T) bool) map[int]T
```
FindAll is like FindIndex, but returns into a map all the values which satisfies the conditional logic of the callback function. The map key represents the position of the found value and the value is the item itself.
<details><summary>Example</summary>
<p>
```go
{
input := []int{1, 2, 3, 4, 2, -2, -1, 2}
items := FindAll(input, func(v int) bool {
return v == 2
})
fmt.Println(items)
}
```
#### Output
```
map[1:2 4:2 7:2]
```
</p>
</details>
## func [FindByKey](<https://github.com/esimov/gogu/blob/master/map.go#L167>)
```go
func FindByKey[K comparable, V any](m map[K]V, fn func(K) bool) map[K]V
```
FindByKey is like Find, but returns the first item for which the callback function returns true.
## func [FindIndex](<https://github.com/esimov/gogu/blob/master/find.go#L11>)
```go
func FindIndex[T any](s []T, fn func(T) bool) int
```
FindIndex returns the index of the first found element.
## func [FindKey](<https://github.com/esimov/gogu/blob/master/map.go#L155>)
```go
func FindKey[K comparable, V any](m map[K]V, fn func(V) bool) K
```
FindKey is like Find, but returns the first item key position for which the callback function returns true.
## func [FindLastIndex](<https://github.com/esimov/gogu/blob/master/find.go#L21>)
```go
func FindLastIndex[T any](s []T, fn func(T) bool) int
```
FindLastIndex is like FindIndex, only that returns the index of last found element.
## func [FindMax](<https://github.com/esimov/gogu/blob/master/find.go#L103>)
```go
func FindMax[T constraints.Ordered](s []T) T
```
FindMax finds the maximum value of a slice.
## func [FindMaxBy](<https://github.com/esimov/gogu/blob/master/find.go#L120>)
```goFrequently Asked Questions
What is gogu?
gogu is a Data Structures and Algorithms library for the Go programming language. A comprehensive, reusable and efficient concurrent-safe generics utility functions and data structures library
How do I install gogu?
Install gogu with the Go module system using `go get esimov/gogu`. Check the repository for the current installation instructions.
What category does gogu belong to?
gogu is listed under Data Structures and Algorithms, specifically Miscellaneous Data Structures and Algorithms.