underscore

package module
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Nov 16, 2025 License: MIT Imports: 7 Imported by: 28

README

_Underscore

License Go version Go report test coverage OpenSSF Best Practices

underscore

underscore is a Go library providing useful functional programming helpers without extending any built-in objects.

It is mostly a port from the underscore.js library based on generics brought by Go 1.18.

Usage

📚 Follow this link for the documentation.

Install the library using

go get github.com/rjNemo/underscore@latest

Please check out the examples to see how to use the library.

package main

import (
 "fmt"
 u "github.com/rjNemo/underscore"
)

func main() {
 numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
 // filter even numbers from the slice
 evens := u.Filter(numbers, func(n int) bool { return n%2 == 0 })
 // square every number in the slice
 squares := u.Map(evens, func(n int) int { return n * n })
 // reduce to the sum
 res := u.Reduce(squares, func(n, acc int) int { return n + acc }, 0)

 fmt.Println(res) // 120
}

Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

Prerequisites

You need at least go1.24 for development. The project is shipped with a Dockerfile based on go1.24.

If you prefer local development, navigate to the official download page and install version 1.24 or beyond.

Installing

First clone the repository

git clone https://github.com/rjNemo/underscore.git

Install dependencies

go mod download

And that's it.

Tests

To run the unit tests, you can simply run:

make test

Functions

underscore provides many of functions that support your favorite functional helpers

Collections
  • All
  • Any
  • Chunk
  • Contains
  • ContainsBy
  • Count
  • Difference
  • Drop
  • Each
  • Filter
  • Find
  • Flatmap
  • GroupBy
  • Intersection
  • Join / JoinProject
  • Last
  • Map
  • Max
  • Min
  • OrderBy
  • Partition
  • Range
  • Reduce
  • RemoveAt
  • Sum / SumMap
  • Unique
  • UniqueBy
  • UniqueInPlace
  • Zip
Pipe

Calling NewPipe will cause all future method calls to return wrapped values. When you've finished the computation, call Value to retrieve the final value.

Methods not returning a slice such as Reduce, All, Any, will break the Chain and return Value instantly.

Concurrency
  • ParallelMap(ctx, values, workers, fn): apply a function concurrently while preserving order and supporting context cancellation.
  • ParallelFilter(ctx, values, workers, fn): filter concurrently with order preserved and context support.
package main

import (
 "context"
 "fmt"
 u "github.com/rjNemo/underscore"
)

func main() {
 out, err := u.ParallelMap(context.Background(), []int{1, 2, 3, 4}, 4,
  func(ctx context.Context, n int) (int, error) { return n * n, nil },
 )
 fmt.Println(out, err) // [1 4 9 16] <nil>
}
// ParallelFilter example
package main

import (
 "context"
 "fmt"
 u "github.com/rjNemo/underscore"
)

func main() {
 out, err := u.ParallelFilter(context.Background(), []int{1,2,3,4,5}, 3,
  func(ctx context.Context, n int) (bool, error) { return n%2==0, nil },
 )
 fmt.Println(out, err) // [2 4] <nil>
}
Utilities
  • Ternary: conditional expression helper
  • ToPointer: convert values to pointers
  • SortSliceASC / SortSliceDESC: sort slices in ascending or descending order
  • Result, Ok, Err, ToResult: Result type for error handling
  • Tuple: generic tuple type for paired values
Subpackages
  • maps.Keys(m) / maps.Values(m): extract keys or values from maps
  • maps.Map(m, fn): transform map entries

Built With

  • Go - Build fast, reliable, and efficient software at scale

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

  • Ruidy - Initial work - Ruidy

See also the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

This project is largely inspired by Underscore.js library. Check out the original project if you don't already know it.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrEmptySlice = errors.New("underscore: empty slice")

ErrEmptySlice is returned when trying to get the first element of an empty slice

Functions

func All

func All[T any](values []T, predicate func(T) bool) bool

All returns true if all the values in the slice pass the predicate truth test. Short-circuits and stops traversing the slice if a false element is found.

func Any

func Any[T any](values []T, predicate func(T) bool) bool

Any returns true if any of the values in the slice pass the predicate truth test. Short-circuits and stops traversing the slice if a true element is found.

func Chunk added in v0.8.0

func Chunk[T any](values []T, n int) [][]T

Chunk splits the input slice into groups of size n. If n <= 0, it returns nil. The final chunk may be smaller than n.

func Contains

func Contains[T comparable](values []T, value T) bool

Contains returns true if the value is present in the slice

func ContainsBy added in v0.8.0

func ContainsBy[T any](values []T, predicate func(T) bool) bool

ContainsBy returns true if any element in the slice satisfies the predicate.

func Count added in v0.6.0

func Count[T any](slice []T, predicate func(T) bool) int

Count returns the number of elements in the slice that satisfy the predicate. example: Count([]int{1,2,3,4,5}, func(n int) bool { return n%2 == 0 }) // 2

func Difference

func Difference[T comparable](slice, other []T) []T

Difference Returns a copy of the array with all instances of the values that are not present in the other array.

func Drop

func Drop[T any](values []T, n int) []T

Drop returns a new slice with the first n elements removed. If n is greater than or equal to the slice length, returns an empty slice. If n is less than or equal to 0, returns the original slice.

func DropWhile added in v0.10.0

func DropWhile[T any](values []T, predicate func(T) bool) []T

DropWhile drops elements from the beginning of the slice while the predicate returns true. It returns the remaining elements starting from the first element where the predicate returns false.

func Each

func Each[T any](values []T, action func(T)) []T

Each iterates over a slice of elements, yielding each in turn to an action function. Returns the slice for piping.

func Filter

func Filter[T any](values []T, predicate func(T) bool) (res []T)

Filter looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate).

func Find

func Find[T any](values []T, predicate func(T) bool) (res T, err error)

Find looks through each value in the slice, returning the first one that passes a truth test (predicate), or the default value for the type and an error if no value passes the test. The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice.

func First added in v0.10.0

func First[T any](values []T) (T, error)

First returns the first element of the slice. Returns an error if the slice is empty.

func FirstN added in v0.10.0

func FirstN[T any](values []T, n int) []T

FirstN returns the first n elements of the slice. If n is greater than the slice length, returns the entire slice. If n is less than or equal to 0, returns an empty slice.

func Flatmap added in v0.5.0

func Flatmap[T any](values []T, mapper func(n T) []T) []T

Flatmap flatten the input slice element into the new slice. FlatMap maps every element with the help of a mapper function, then flattens the input slice element into the new slice.

func FoldRight added in v0.10.0

func FoldRight[T, P any](values []T, acc P, fn func(T, P) P) P

FoldRight is like Reduce but processes elements from right to left. Also known as foldr in Haskell.

Example: FoldRight([]int{1,2,3}, 0, func(n, acc int) int { return n - acc })

→ 1 - (2 - (3 - 0)) = 1 - (2 - 3) = 1 - (-1) = 2

func GroupBy

func GroupBy[K comparable, V any](values []V, f func(V) K) map[K][]V

GroupBy splits a slice into a map[K][]V grouped by the result of the iterator function.

func Init added in v0.10.0

func Init[T any](values []T) ([]T, T)

Init returns all elements except the last one, and the last element separately. Returns an empty slice and zero value if the input slice is empty. Also known as "uncons from the right" or "snoc" inverse.

func Intersection

func Intersection[T comparable](a, b []T) (res []T)

Intersection computes the list of values that are the intersection of all the slices. Each value in the result is present in each of the slices.

func Intersperse added in v0.10.0

func Intersperse[T any](values []T, separator T) []T

Intersperse inserts a separator between each element of the slice. Returns an empty slice if the input is empty. Returns the original element if the input has only one element.

Example: Intersperse([]int{1,2,3}, 0) → [1, 0, 2, 0, 3]

func JoinProject added in v0.5.0

func JoinProject[L, R, O any, S comparable](
	left []L,
	right []R,
	leftSelector func(L) S,
	rightSelector func(R) S,
	projection func(Tuple[L, []R]) O,
) (results []O)

JoinProject joins two slices together and returns a []O where O is defined by the output of your projection function The selectors allow you to pick the keys from your structure to use as the join keys While the projection functions allows you to reformat joined datasets (Tuple of [T, []P]) into your own struct or type

func Last

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

Last returns the last element of the slice. Panics if the slice is empty.

func Map

func Map[T, P any](values []T, transform func(T) P) []P

Map produces a new slice of values by mapping each value in the slice through a transform function.

func Max

func Max[T cmp.Ordered](values []T) T

Max returns the maximum value in the slice. Panics if values is empty. This function can currently only compare numbers reliably. This function uses operator <.

func Min

func Min[T cmp.Ordered](values []T) T

Min returns the minimum value in the slice. Panics if values is empty. This function can currently only compare numbers reliably. This function uses operator <.

func OrderBy added in v0.5.0

func OrderBy[T any](list []T, predicate func(T, T) bool) []T

OrderBy orders a slice by a field value within a struct, the predicate allows you to pick the fields you want to orderBy. Use > for ASC or < for DESC Uses O(n log n) sorting algorithm. Mutates the input slice.

func (left Person, right Person) bool { return left.Age > right.Age }

func ParallelFilter added in v0.8.0

func ParallelFilter[T any](ctx context.Context, values []T, workers int, fn func(context.Context, T) (bool, error)) ([]T, error)

ParallelFilter filters values using a context-aware predicate concurrently and preserves input order. If workers <= 0, it defaults to GOMAXPROCS. On error, cancels work and returns nil with the error.

func ParallelMap added in v0.8.0

func ParallelMap[T, P any](ctx context.Context, values []T, workers int, fn func(context.Context, T) (P, error)) ([]P, error)

ParallelMap applies fn to each element of values using a worker pool and preserves order. If workers <= 0, it defaults to GOMAXPROCS. On error, the first error is returned and processing is canceled; partial results are discarded.

func ParallelReduce added in v0.10.0

func ParallelReduce[T, P any](ctx context.Context, values []T, workers int, fn func(context.Context, T, P) (P, error), acc P) (P, error)

ParallelReduce applies a reduction function in parallel using a worker pool. The operation must be associative and commutative for correct results. If workers <= 0, defaults to GOMAXPROCS. On error, the first error is returned and processing is canceled.

Note: Order of operations is not guaranteed, so use only with associative/commutative operations.

func Partition

func Partition[T any](values []T, predicate func(T) bool) ([]T, []T)

Partition splits the slice into two slices: one whose elements all satisfy predicate and one whose elements all do not satisfy predicate.

func Range added in v0.5.0

func Range(start int, end int) (result []int)

Range creates a sequence of numbers, i.e. u.Range(0, 3) = [0 1 2 3], while u.Range(3, 0) = [3 2 1 0]

func Reduce

func Reduce[T, P any](values []T, reduction func(T, P) P, acc P) P

Reduce combine a list of values into a single value. acc is the initial state, and each successive step of it should be returned by the reduction function.

func RemoveAt added in v0.9.0

func RemoveAt[T any](values []T, index int) []T

RemoveAt returns a new slice with the element at the given index removed. Returns original slice if index is out of bounds.

func Replicate added in v0.10.0

func Replicate[T any](count int, value T) []T

Replicate creates a slice containing count copies of value. Returns an empty slice if count is less than or equal to 0.

Example: Replicate(3, "hello") → ["hello", "hello", "hello"]

func Scan added in v0.10.0

func Scan[T, P any](values []T, acc P, fn func(P, T) P) []P

Scan is like Reduce but returns all intermediate accumulator values. Also known as prefix scan or cumulative fold.

Example: Scan([]int{1,2,3,4}, 0, func(acc, n int) int { return acc + n }) → [1, 3, 6, 10]

func Sliding added in v0.10.0

func Sliding[T any](values []T, size int) [][]T

Sliding creates a sliding window view of the slice with the specified window size. Returns an empty slice if size is less than or equal to 0. Returns an empty slice if size is greater than the slice length.

Example: Sliding([]int{1,2,3,4,5}, 3) → [[1,2,3], [2,3,4], [3,4,5]]

func SortSliceASC added in v0.7.0

func SortSliceASC[T cmp.Ordered](s []T)

SortSliceASC sorts any slice ASCENDING

func SortSliceDESC added in v0.7.0

func SortSliceDESC[T cmp.Ordered](s []T)

SortSliceDESC sorts any slice DESCENDING

func Sum

func Sum[T cmp.Ordered](values []T) (sum T)

Sum adds elements of the slice.

func SumMap added in v0.5.0

func SumMap[T any, R cmp.Ordered](list []T, selector func(T) R) (sum R)

SumMap sums the values you select from your struct, basically a sort cut instead of having to perform a Map followed by a Sum.

func TakeWhile added in v0.10.0

func TakeWhile[T any](values []T, predicate func(T) bool) []T

TakeWhile returns elements from the beginning of the slice while the predicate returns true. It stops at the first element where the predicate returns false.

func Tap added in v0.10.0

func Tap[T any](values []T, fn func(T)) []T

Tap applies a function to each element for side effects (like debugging/logging) and returns the original slice unchanged. Useful for debugging pipelines.

Example: Tap([]int{1,2,3}, func(n int) { fmt.Println(n) }) → [1,2,3] (and prints each)

func Ternary

func Ternary[T any](condition bool, pos, neg T) T

Ternary returns the first argument if the condition is true, otherwise the second argument. Ternary is a special form of the if statement. It allows you to write code that is more concise and less verbose.

func ToPointer added in v0.7.0

func ToPointer[T any](in T) *T

ToPointer Convert values to pointers

Instead of: v := "value" MyPointerVar = &v

Or v1 := "value1" v2 := 100

obj := Obj{
	Field1: &v,
	Field2: &v2,
}

Use: MyPointerVar = ToPointer("value")

func Transpose added in v0.10.0

func Transpose[T any](matrix [][]T) [][]T

Transpose flips a matrix over its diagonal, swapping rows and columns. Returns an empty slice if the input is empty. Assumes all rows have the same length (uses the length of the first row).

Example: Transpose([[1,2,3], [4,5,6]]) → [[1,4], [2,5], [3,6]]

func Unique

func Unique[T comparable](values []T) (uniques []T)

Unique returns a slice of unique values from the given slice.

func UniqueBy added in v0.8.0

func UniqueBy[T any, K comparable](values []T, key func(T) K) (uniques []T)

UniqueBy returns a slice of unique values from the given slice using a key selector. The first occurrence of each key is kept and order is preserved.

func UniqueInPlace added in v0.8.0

func UniqueInPlace[T comparable](values []T) []T

UniqueInPlace removes duplicate elements from the slice in place, preserving order. It returns the shortened slice containing the first occurrence of each value.

func Unzip added in v0.10.0

func Unzip[L, R any](pairs []Tuple[L, R]) ([]L, []R)

Unzip splits a slice of tuples into two separate slices. The inverse operation of Zip.

Example: Unzip([Tuple{1,"a"}, Tuple{2,"b"}]) → ([1,2], ["a","b"])

Types

type Err

type Err[T any] struct{ Err error }

Err is the Result that represents failure. It implements the error interface

func (Err[T]) Error

func (e Err[T]) Error() string

func (Err[T]) IsSuccess

func (e Err[T]) IsSuccess() bool

func (Err[T]) ToValue

func (e Err[T]) ToValue() (*T, error)

type Ok

type Ok[T any] struct {
	Value *T
}

Ok is the Result that represents success.

func (Ok[T]) IsSuccess

func (o Ok[T]) IsSuccess() bool

func (Ok[T]) ToValue

func (o Ok[T]) ToValue() (*T, error)

type Pipe

type Pipe[T cmp.Ordered] struct {
	Value []T
}

func NewPipe

func NewPipe[T cmp.Ordered](value []T) Pipe[T]

NewPipe starts a Pipe. All future method calls will return Pipe structs. When you've finished the computation, call Value to retrieve the final value.

Methods not returning a slice such as Reduce, All, Any, will break the Pipe and return Value instantly.

func (Pipe[T]) All

func (c Pipe[T]) All(predicate func(T) bool) bool

All returns true if all the values in the slice pass the predicate truth test. Short-circuits and stops traversing the slice if a false element is found. Breaks the Pipe.

func (Pipe[T]) Any

func (c Pipe[T]) Any(predicate func(T) bool) bool

Any returns true if any of the values in the slice pass the predicate truth test. Short-circuits and stops traversing the slice if a true element is found. Breaks the Pipe.

func (Pipe[T]) Contains

func (c Pipe[T]) Contains(value T) bool

Contains returns true if the value is present in the slice and breaks the Pipe.

func (Pipe[T]) Each

func (c Pipe[T]) Each(action func(T))

Each iterates over a slice of elements, yielding each in turn to an action function. Breaks the Pipe.

func (Pipe[T]) Filter

func (c Pipe[T]) Filter(predicate func(n T) bool) Pipe[T]

Filter looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate).

func (Pipe[T]) Find

func (c Pipe[T]) Find(predicate func(n T) bool) (T, error)

Find looks through each value in the slice, returning the first one that passes a truth test (predicate), or the default value for the type and an error if no value passes the test. The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice. Breaks the Pipe.

func (Pipe[T]) Map

func (c Pipe[T]) Map(transform func(n T) T) Pipe[T]

Map produces a new slice of values by mapping each value in the slice through a transform function.

TODO: Move from T to P.

func (Pipe[T]) Max

func (c Pipe[T]) Max() T

Max returns the maximum value in the slice. This function can currently only compare numbers reliably. This function uses operator <. Breaks the Pipe.

func (Pipe[T]) Min

func (c Pipe[T]) Min() T

Min returns the minimum value in the slice. This function can currently only compare numbers reliably. This function uses operator <. Breaks the Pipe.

func (Pipe[T]) Partition

func (c Pipe[T]) Partition(predicate func(T) bool) ([]T, []T)

Partition splits the slice into two slices: one whose elements all satisfy predicate and one whose elements all do not satisfy predicate. Breaks the Pipe.

func (Pipe[T]) Reduce

func (c Pipe[T]) Reduce(reducer func(n, acc T) T, acc T) T

Reduce combine a list of values into a single value and breaks the Pipe. acc is the initial state, and each successive step of it should be returned by the reduction function.

type Result

type Result[T any] interface {
	ToValue() (*T, error)
	IsSuccess() bool
	// contains filtered or unexported methods
}

Result represent the outcome of an operation where failure is possible

func ToResult

func ToResult[T any](value *T, err error) Result[T]

type Tuple added in v0.5.0

type Tuple[L, R any] struct {
	Left  L
	Right R
}

Tuple is a generic tuple type. It is used to return multiple values from a function.

func Join added in v0.5.0

func Join[T, P any, S comparable](
	left []T,
	right []P,
	leftSelector func(T) S,
	rightSelector func(P) S,
) []Tuple[T, []P]

Join joins two slices together and returns a Tuple of [T, []P], the selectors allow you to pick the keys you want to use from your struct's to join the sets together

func Zip added in v0.5.0

func Zip[L any, R any](left []L, right []R) []Tuple[L, R]

Zip joins two slices together so all the elements of left slice are attached to the corresponding elements of the right slice, i.e. [one two three] [1 2 3 4] = [{one, 1} {two, 2} {three, 3}] the returned data will be the size of the smallest slice

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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