list

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Dec 23, 2023 License: MIT Imports: 7 Imported by: 0

README

Go Reference

Functional Lists

This package provides many generic functions for working with slices. The API here is mostly inspired by the list library in the F# standard library. There are some minor changes and the implementation is just how I thought it should be done. Several of these functions may not be very useful in Go but I have included them for the sake of having a complete set of functions that can be passed around when needed. You can generally just copy the function definition into your own code. That will also protect against changes in the API which may happen in the future. This is a very early version and may or may not be changed in the future as I see a need.

Installation

go get -u github.com/flowonyx/functional/list

Terminology

  • A projection just means a function that takes a certain type and returns another type.
    • This is often used to return one field from the type for use in different functions.
    • It can also return the whole value wrapped in another type.
    • It can also return something completely different, such as a projection of a string where it returns the length.
  • A predicate is a function that returns a boolean (true or false), generally based on one or two parameters.
  • Many functions have a variation which begin with Try.
    • These functions return option.Option values which are None if they fail to find something.
    • You can see the option package for more information about how to work with this.
  • Some functions have a variation which begin with Must.
    • These functions panic instead of returning an error.
  • Some functions have a variation which ends with By.
    • These functions take a projection function to get the values to use.

Functions

  • Average returns the average of the items in any numeric slice.

  • CountBy applies a projection to each value in a slice and uses the result as the key in map of counts.

  • Sum returns the result of adding all values in a numeric slice together. (It can also concatenate strings.)

  • SumBy returns the result of adding all results from a given projection function to each value in a slice.

  • Min returns the minimum value of all items. The only time an error will be returned is when no values are passed. If you know you are passing it values, you can either ignore the error value or use the MustMin variation instead.

  • Max returns the maximum value of all items. Everything said about Min applies to this as well.

  • Average returns the average of the items in any numeric slice.

  • CountBy applies a projection to each value in a slice and uses the result as the key in map of counts.

  • Sum returns the result of adding all values in a numeric slice together. (It can also concatenate strings.)

  • SumBy returns the result of adding all results from a given projection function to each value in a slice.

  • Min returns the minimum value of all items. The only time an error will be returned is when no values are passed. If you know you are passing it values, you can either ignore the error value or use the MustMin variation instead.

  • Max returns the maximum value of all items. Everything said about Min applies to this as well.

  • Average returns the average of the items in any numeric slice.

  • CountBy applies a projection to each value in a slice and uses the result as the key in map of counts.

  • Sum returns the result of adding all values in a numeric slice together. (It can also concatenate strings.)

  • SumBy returns the result of adding all results from a given projection function to each value in a slice.

  • Min returns the minimum value of all items. The only time an error will be returned is when no values are passed. If you know you are passing it values, you can either ignore the error value or use the MustMin variation instead.

  • Max returns the maximum value of all items. Everything said about Min applies to this as well.

Selecting and checking for existence

  • Choose returns a slice of values from an input slice that match the given predicate function (it does not return None).
  • Pick returns the first value from an input slice that matches the given predicate function (it does not return None).
  • Contains tests whether a value is within a slice.
  • Distinct returns a copy of a slice with any duplicate values removed.
  • Except returns values that are not in a slice of values to exclude.
  • Exists tests whether any value in a slice matches a predicate.
  • Filter returns the values in a slice that match a predicate.
  • Find and its variants returns the first value that matches a predicate. (It is the same as Pick except that the predicate does not return an Option.)
  • FindBack and and its variants returns the last value that matches a predicate.
  • ForAll tests whether all values in a slice match a predicate.
  • IndexOf returns the first index within a slice that matches a value. There are several variants of this, including IndexOfBack which searches backwards from the end of the slice.
  • Skip returns a clone of a slice after skipping the number of items requested. It will panic if count is greater than the length of the slice.
  • SkipWhile returns a clone of a slice starting from where a provided predicate returns false.
  • Take returns an option.Option of the first values in a slice up to a given count. It returns an option.Option so it will not need to return an error if count is out of bounds. (See Truncate for ignoring the error.)
    • TakeWhile returns the first values in a slice until a given predicate function returns false.
    • Truncate returns the first values in a slice up to a given count. If the count exceeds the number of values in the slice, it will return all the values.

Rearranging slices

  • AllPairs returns a new slice that contains all pairings of elements from two slices.
  • ChunkBySize returns a two dimensional slice where each sub slice is a "chunk" of the input slice of the specified size.
  • Collect takes a projection function that returns a slice for each item in a given slice. After applying the projection to each item, Collect then returns all the generated slices concatenated together.
  • Concat accepts any number of slices and concatenates them into a single slice.
  • GroupBy applies a projection to each value in a slice and returns a slice of functional.Pairs where each Pair is a key and a slice of values for which the projection returned that key.
    • You can get the results returned as a map by using GroupByAsMap.
  • Indexed converts a slice into a a slice of functional.Pairs where the first part is the index and the second part is the item.
  • Pairwise returns a slice of each item in the input slice and the one before it, except for the first item which is only returned as the one before the second element.
  • Partition splits the slice into two slices. The first slice contains the items for which the given predicate returns true, and the second slice contains the items for which the given predicate returns false respectively.
  • Reverse returns a clone of a slice with the order of the items reversed.
  • Sort returns a clone of a slice of any ordered type in sorted order.
    • SortDescending returns a clone of a slice of any ordered type in reverse sorted order.
    • SortBy returns a clone of a slice of any type (it does not have to be constraints.Ordered) sorted in ascending order based on the key returned from a projection function.
    • SortByDescending is obviously the same as SortBy but in reverse order.
    • SortWith returns a clone of a slice of any type (it does not have to be constraints.Ordered) sorted in the order as determined by the less function you provide.
  • SplitAt splits a slice at a given index into two separate slices.
  • SplitInto splits a slice into a series of slices of whatever length is necessary to have the given number of slices.
  • Windowed returns the values in sliding windows of a specified size.
  • Zip puts two slices into one slice of functional.Pairs.
    • Unzip takes a slice of functional.Pairs and returns two slices as they would have been before a Zip operation.
    • Zip3 and Unzip3 are the same except that they work on three slices and functional.Triples.

Generating slices and setting indexes

  • Cons takes a Head and a Tail and puts them together into one slice.
  • Create and its variations creates a slice with all values set to the supplied value.
  • CreateZero and its variations creates a slice with all values set to the zero value of the slice.
  • CreateFromStructure2D and CreateFromStructure3D creates a 2 dimensional or 3 dimensional slice of the same dimensions as the slice passed in.
  • Empty makes a slice with the given cap but length of 0. This is helpful for when you need to use append to fill out the slice because it is difficult to figure out the index but you know the size ahead of time.
  • Fill fills the range of items in a slice from a start index for the specified number of items with a given value.
  • InitSlice makes a new slice of a specified length and initializes the values with the return value of an initializer function which is given the index of the item.
    • There are several variants for different dimensions of slices.
  • InsertAt and RemoveAt and their variants just simplify the syntax for placing items or removing them at specific indexes in a slice.
  • SetItem and its variants (SetItem2D etc.) are equivalent to simply setting an index in a slice to the given value except that instead of panicking, it returns an errors.IndexOutOfRangeErr error.
  • UpdateItem and its variants are the same as SetItem but they return a clone of the slice with the change updated instead of changing the original slice.
  • Singleton creates a slice with a single value in it.
    • ExactlyOne checks if a slice has exactly one value in it and it does, returns the slice. If it does not, it returns a errors.BadArgumentErr error.

Comparing slices

  • Equal compares two slices and returns true if they have the same values in the same order.
  • EqualUnordered compares two slices and returns true if they have the same values in any order.
  • MinLen returns the minimum length of any number of slices.
  • MinSlice returns the slice of any number of slices that has the minimum length.

Properties of a slice

  • Len2, Len3, and Len4 gets the minimum length of the sub slices in the two, three, or four dimensional slice.
  • LastIndexOf is basically just len(slice)-1, but I like the way it reads better and I don't have to worry about forgetting the -1.
  • Head gets the first item in a slice. It will return an error if the slice is empty. If you want to ignore the error, you can use MustHead instead.
  • Last gets the last item in a slice. It will return an error if the slice is empty. If you want to ignore the error, you can use MustLast instead.
  • Tail gets the items in the slice after the first item (Head). If the slice is empty, it will just return an empty slice.

Operations over a slice

  • Average returns the average of the items in any numeric slice.
  • CountBy applies a projection to each value in a slice and uses the result as the key in map of counts.
  • Fold and its variants apply a folding function to each item in a slice and keep changing the state each time. It then returns the final state.
  • Iter iterates over all items in a slice, applying a function to each value that returns nothing. There are several variants, including IterRev which iterates backwards over the slice.
  • IterUntil iterates over each item in a slice until the function applied to it returns true.
  • Map and its variants applies a mapping function to each item in a slice and returns the results as a new slice. The returned slice can be of a completely different type from the original slice.
  • Permute returns a slice with all items rearranged by function that accepts the original index and returns the new index.
  • Range creates a slice of Integers from a specified start to a specified end. If a step value is specified, the values will be spaced by that amount.
  • RangeTo is the same as Range except you do not need to specify the start value--it will start at 0 and the step will always be 1.
    • The variants that begin with DoRange execute a function which is passed each number in the range.
  • Sum returns the result of adding all values in a numeric slice together. (It can also concatenate strings.)
  • SumBy returns the result of adding all results from a given projection function to each value in a slice.
  • Transpose returns the transpose of the sequence of slices.
  • Min returns the minimum value of all items. The only time an error will be returned is when no values are passed. If you know you are passing it values, you can either ignore the error value or use the MustMin variation instead.
  • Max returns the maximum value of all items. Everything said about Min applies to this as well.

Documentation

Overview

Package list provides generic functions for dealing with slices. The API is basically ripped off of F#.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllPairs

func AllPairs[T, T2 any](input1 []T, input2 []T2) []Pair[T, T2]

AllPairs returns a slice of all pairs of items from two slices.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []int{1, 2}
	input2 := []int{3, 4}
	r := list.AllPairs(input1, input2)
	fmt.Println(r)
}
Output:

[(1, 3) (1, 4) (2, 3) (2, 4)]

func Average

func Average[T numeric](values ...T) T

Average calculates the average of all provided values.

Example
fmt.Println(Average(1, 2, 3, 4, 5))
Output:

3

func AverageBy

func AverageBy[T any, R numeric](projection func(T) R, values ...T) R

AverageBy applies projection to each value to get the numeric value to be used in the average calculation.

Example
fmt.Println(AverageBy(func(t uint) float64 {
	return float64(t) * 0.5
}, []uint{1, 2, 3, 4, 5}...))
Output:

1.5

func Choose

func Choose[T any, R any](chooser func(T) option.Option[R], values []T) []R

Choose applies chooser to each value in values and if chooser returns Some, it includes the returned value in a new slice.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/flowonyx/functional/list"
	"github.com/flowonyx/functional/option"
)

func main() {
	i := list.Choose(func(s string) option.Option[int] {
		if i, err := strconv.Atoi(s); err == nil {
			return option.Some(i)
		}
		return option.None[int]()
	}, []string{"zero", "1", "2", "three", "4"})

	fmt.Println(i)
}
Output:

[1 2 4]

func ChunkBySize

func ChunkBySize[T any](chunkSize int, values []T) [][]T

ChunkBySize accepts a slice of values and returns a two dimensional slice where each inner slice has the length of chunkSize or smaller if at end of values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	chunks := list.ChunkBySize(2, []int{1, 2, 3, 4, 5, 6, 7, 8, 9})
	fmt.Println(chunks)
}
Output:

[[1 2] [3 4] [5 6] [7 8] [9]]

func Collect

func Collect[T any, R any](projection func(T) []R, input []T) []R

Collect applies projection to a slice of values. projection returns a slice for each value, which then are all concatenated into one slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	type foo struct {
		Bar []int
	}
	input := []foo{
		{Bar: []int{1, 2}},
		{Bar: []int{3, 4}},
	}
	r := list.Collect(func(f foo) []int { return f.Bar }, input)
	fmt.Println(r)
}
Output:

[1 2 3 4]

func Concat

func Concat[T any](values ...[]T) []T

Concat accepts any number of slices and concatenates them into a single slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	inputs := [][]int{{1, 2}, {3}, {4, 5}}
	r := list.Concat(inputs...)
	fmt.Println(r)
}
Output:

[1 2 3 4 5]

func Cons

func Cons[T any](head T, tail []T) []T

Cons makes a new list with head at the beginning and the items in tail after that.

func ConsPair

func ConsPair[T any](p functional.Pair[T, []T]) []T

ConsPair makes a new list with the first item in the Pair at the beginning and the items in the second item in the Pair after that.

func Contains

func Contains[T comparable](search T, values ...T) bool

Contains tests whether search is within values.

Example
input := []int{1, 2, 3, 4, 5, 6}
r1 := Contains(3, input...)
r2 := Contains(7, input...)
fmt.Println(r1, r2)
Output:

true false

func CountBy

func CountBy[T any, Key comparable](projection func(T) Key, values ...T) map[Key]int

CountBy applies projection to each value and uses the result as the key in map of counts.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	type foo struct {
		Bar string
	}

	input := []foo{{Bar: "a"}, {Bar: "b"}, {Bar: "a"}}

	c := list.CountBy(func(f foo) string { return f.Bar }, input...)
	fmt.Println(c)
}
Output:

map[a:2 b:1]

func Create

func Create[T any](length int, value T) []T

Create makes a slice of the given length with each item set to value.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	a := list.Create(4, "a")
	fmt.Println(a)
}
Output:

[a a a a]

func Create2D

func Create2D[T any](length1, length2 int, value T) [][]T

Create2D makes a two dimensional slice of the given lengths with each item set to value.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	a := list.Create2D(4, 4, "a")
	fmt.Println(a)
}
Output:

[[a a a a] [a a a a] [a a a a] [a a a a]]

func Create3D

func Create3D[T any](length1, length2, length3 int, value T) [][][]T

Create3D makes a three dimensional slice of the given lengths with each item set to value.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	a := list.Create3D(2, 2, 2, "a")
	fmt.Println(a)
}
Output:

[[[a a] [a a]] [[a a] [a a]]]

func Create4D

func Create4D[T any](length1, length2, length3, length4 int, value T) [][][][]T

Create4D makes a four dimensional slice of the given lengths with each item set to value.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	a := list.Create4D(2, 2, 2, 2, "a")
	fmt.Println(a)
}
Output:

[[[[a a] [a a]] [[a a] [a a]]] [[[a a] [a a]] [[a a] [a a]]]]

func CreateFromStructure2D

func CreateFromStructure2D[T, R any](structure [][]T) [][]R

CreateFromStructure2D makes a two dimensional slice sized according the lengths in structure.

func CreateFromStructure3D

func CreateFromStructure3D[T, R any](structure [][][]T) [][][]R

CreateFromStructure3D makes a three dimensional slice sized according the lengths in structure.

func Distinct

func Distinct[T comparable](values ...T) []T

Distinct returns the values without repitition.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	d := list.Distinct(1, 2, 3, 2, 3, 4)
	fmt.Println(d)
}
Output:

[1 2 3 4]

func DistinctBy

func DistinctBy[T any, Key comparable](projection func(T) Key, values ...T) []T

DistinctBy applies projection to each value and returns the values whose projected value is not repeated.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/flowonyx/functional/list"
)

func main() {
	d := list.DistinctBy(func(i int) string { return "s:" + strconv.Itoa(i) }, 1, 2, 3, 2, 3, 4)
	fmt.Println(d)
}
Output:

[1 2 3 4]

func DoRange

func DoRange[TInt constraints.Integer](f func(TInt), start, end TInt, step ...int)

DoRange calls f repeatedly with values from start to end. If step is specified, the values will be spaced by that amount.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	list.DoRange(func(i int) { fmt.Print(i) }, 2, 5)
}
Output:

2345

func DoRangeTo

func DoRangeTo[TInt constraints.Integer](f func(TInt), end TInt)

DoRangeTo calls f repeatedly with values from 0 to end.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	list.DoRangeTo(func(i int) { fmt.Print(i) }, 4)
}
Output:

01234

func DoRangeToRev

func DoRangeToRev[TInt constraints.Integer](f func(TInt), end TInt)

DoRangeToRev calls f repeatedly with values from end to 0.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	list.DoRangeToRev(func(i int) { fmt.Print(i) }, 4)
}
Output:

43210

func DoRangeUntil

func DoRangeUntil[TInt constraints.Integer](f func(TInt) bool, start, end TInt, step ...int)

DoRangeUntil calls f repeatedly with values from start to end until f returns true. If step is specified, the values will be spaced by that amount.

func Empty

func Empty[T any](cap ...int) []T

Empty makes a slice with the given cap but length of 0.

func Equal

func Equal[T comparable](s1 []T, s2 []T) bool

Equal tests the slices s1 and s2 for equality. They are considered equal only if they contain all the same items in the same order.

Example
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{1, 2, 3, 4, 5}
s3 := []int{1, 2, 3, 4}
s4 := []int{1, 2, 3, 5, 4}

fmt.Println(Equal(s1, s2), Equal(s1, s3), Equal(s1, s4))
Output:

true false false

func EqualUnordered

func EqualUnordered[T comparable](s1 []T, s2 []T) bool

EqualUnordered tests the slices s1 and s2 for equality. They are considered equal only if they contain all the same items but the order does not matter.

Example
s1 := []int{1, 2, 3, 4, 5}
s2 := []int{1, 2, 3, 4, 5}
s3 := []int{1, 2, 3, 4}
s4 := []int{1, 2, 3, 5, 4}

fmt.Println(EqualUnordered(s1, s2), EqualUnordered(s1, s3), EqualUnordered(s1, s4))
Output:

true false true

func ExactlyOne

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

ExactlyOne returns the single item in a slice. If the slice is empty or has more than one item it will return a BadArgumentErr.

func Except

func Except[T comparable](itemsToExclude []T, values ...T) []T

Except returns values that are not in itemsToExclude.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	original := []int{1, 2, 3, 4, 5}
	itemsToExclude := []int{1, 3, 5}
	e := list.Except(itemsToExclude, original...)
	fmt.Println(e)
}
Output:

[2 4]

func Exists

func Exists[T any](predicate func(T) bool, values ...T) bool

Exists tests whether any value in values matches predicate.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	e := list.Exists(func(i int) bool { return i%4 == 0 }, 1, 2, 3, 4, 5)
	fmt.Println(e)
}
Output:

true
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	e := list.Exists(func(i int) bool { return i%6 == 0 }, 1, 2, 3, 4, 5)
	fmt.Println(e)
}
Output:

false

func Exists2

func Exists2[T any](predicate func(T, T) bool, values1 []T, values2 []T) bool

Exists2 tests whether any pair of values from values1 and values2 matches predicate. It will only use pairs of items until the minimum length of values1 and values2.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []int{1, 2}
	input2 := []int{1, 2, 0}
	e := list.Exists2(func(a, b int) bool { return a > b }, input1, input2)
	fmt.Println(e)
}
Output:

false
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []int{1, 4}
	input2 := []int{1, 3, 5}
	e := list.Exists2(func(a, b int) bool { return a > b }, input1, input2)
	fmt.Println(e)
}
Output:

true

func Fill

func Fill[T any](values []T, startIndex int, count int, value T) error

Fill fills the range of values from startIndex to startIndex+count with value. If startIndex is outside the range of indexes in values, it will return an IndexOutOfRangeErr. If count goes beyond the end of values, it flils the end of values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3, 4, 5}
	if err := list.Fill(input, 3, 2, 100); err != nil {
		panic(err)
	}
	fmt.Println(input)
}
Output:

[0 1 2 100 100 5]

func Filter

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

Filter returns the values that match predicate.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3, 4}
	r := list.Filter(func(i int) bool { return i%2 == 0 }, input...)
	fmt.Println(r)
}
Output:

[0 2 4]

func Find

func Find[T any](predicate func(T) bool, input ...T) (T, error)

Find returns the first value that matches predicate. If no values match predicate, it returns a NotFoundErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func mod2(i int) bool { return i%2 == 0 }

func main() {
	r, err := list.Find(mod2, 1, 2, 3, 4)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

2
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/errors"
	"github.com/flowonyx/functional/list"
)

func mod6(i int) bool { return i%6 == 0 }

func main() {
	_, err := list.Find(mod6, 1, 2, 3)
	fmt.Println(errors.Is(err, errors.NotFoundErr))
}
Output:

true

func FindBack

func FindBack[T any](predicate func(T) bool, input ...T) (T, error)

FindBack returns the last value that matches predicate. If no values match predicate, it returns a NotFoundErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func mod2(i int) bool { return i%2 == 0 }

func main() {
	r, err := list.FindBack(mod2, 1, 2, 3, 4)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

4

func Fold

func Fold[State any, T any](folder func(State, T) State, initialState State, values []T) State

Fold applies folder to each value in order starting with initialState.

Example
r := Fold(chargesFolder, 0, []Pair[int, ChargeType]{
	{First: 1, Second: In},
	{First: 2, Second: Out},
	{First: 3, Second: In},
})
fmt.Println(r)
Output:

2

func Fold2

func Fold2[State any, T any, T2 any](folder func(State, T, T2) State, initialState State, values1 []T, values2 []T2) State

Fold2 applies folder to each pair of values from values1 and values2 in order starting with initialState.

Example
data1 := []CoinToss{Tails, Heads, Tails}
data2 := []CoinToss{Tails, Heads, Heads}
r := Fold2(coinTossFolder, 0, data1, data2)
fmt.Println(r)
Output:

1

func FoldBack

func FoldBack[State any, T any](folder func(T, State) State, values []T, initialState State) State

FoldBack applies folder to each value in reverse order starting with initialState.

Example
type Count struct {
	Positive int
	Negative int
	Text     string
}

countFolder := func(a int, acc Count) Count {
	text := acc.Text + " " + strconv.Itoa(a)
	if a >= 0 {
		return Count{
			Positive: acc.Positive + 1,
			Negative: acc.Negative,
			Text:     text,
		}
	}
	return Count{
		Positive: acc.Positive,
		Negative: acc.Negative + 1,
		Text:     text,
	}
}

input := []int{1, 0, -1, -2, 3}
initialState := Count{Positive: 0, Negative: 0, Text: ""}
r := FoldBack(countFolder, input, initialState)
fmt.Println(r.Positive, r.Negative, ":"+r.Text)
Output:

3 2 : 3 -2 -1 0 1

func FoldBack2

func FoldBack2[State any, T any, T2 any](folder func(T, T2, State) State, values1 []T, values2 []T2, initialState State) State

FoldBack2 applies folder to each pair of values from values1 and values2 in reverse order starting with initialState.

Example
type Count struct {
	Positive int
	Negative int
	Text     string
}

countFolder := func(a, b int, acc Count) Count {
	text := acc.Text + "(" + strconv.Itoa(a) + ", " + strconv.Itoa(b) + ") "
	if a+b >= 0 {
		return Count{
			Positive: acc.Positive + 1,
			Negative: acc.Negative,
			Text:     text,
		}
	}
	return Count{
		Positive: acc.Positive,
		Negative: acc.Negative + 1,
		Text:     text,
	}
}

input1 := []int{-1, -2, -3}
input2 := []int{3, 2, 1}
initialState := Count{Positive: 0, Negative: 0, Text: ""}
r := FoldBack2(countFolder, input1, input2, initialState)
fmt.Println(r.Positive, r.Negative, ":"+r.Text)
Output:

2 1 :(-3, 1) (-2, 2) (-1, 3)

func ForAll

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

ForAll tests whether all values match predicate.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.ForAll(list.LessThan(4), []int{1, 2, 3})
	fmt.Println(r)
}
Output:

true
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.ForAll(list.Not(list.LessThan(4)), []int{1, 2, 3})
	fmt.Println(r)
}
Output:

false

func ForAll2

func ForAll2[T any, T2 any](predicate func(T, T2) bool, values1 []T, values2 []T2) bool

ForAll2 tests whether all pairs of values from values1 and values2 match predicate.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.ForAll2(list.ValueEqual2[int], []int{1, 2, 3}, []int{1, 2, 3})
	fmt.Println(r)
}
Output:

true
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.ForAll2(list.ValueEqual2[int], []int{4, 2, 3}, []int{1, 2, 3})
	fmt.Println(r)
}
Output:

false
Example (Third)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.ForAll2(list.GreaterThan2[int], []int{1, 2, 3}, []int{2, 3, 4})
	fmt.Println(r)
}
Output:

true

func GreaterThan

func GreaterThan[T constraints.Ordered](a T) func(T) bool

GreaterThan returns a function that tests whether the value passed the returned function is greater than a. The primary purpose of this function is for use in ForAll or other predicates.

func GreaterThan2

func GreaterThan2[T constraints.Ordered](a, b T) bool

GreaterThan2 tests whether b is greater than a. The primary purpose of this function is for use in ForAll2 or other predicates that accept two parameters.

func GroupBy

func GroupBy[T any, Key comparable](projection func(T) Key, values []T) []Pair[Key, []T]

GroupBy applies projection to each value in values and returns a slice of Pairs where each Pair has a key and a slice of values for which projection returned that key.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.GroupBy(func(i int) int { return i % 2 }, []int{1, 2, 3, 4, 5})
	fmt.Println(r)
}
Output:

[(1, [1 3 5]) (0, [2 4])]

func GroupByAsMap

func GroupByAsMap[T any, Key comparable](projection func(T) Key, input []T) map[Key][]T

GroupAsMap applies projection to each value in values and returns a map where each item has a key and a slice of values for which projection returned that key.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.GroupByAsMap(func(i int) int { return i % 2 }, []int{1, 2, 3, 4, 5})
	fmt.Println(r)
}
Output:

map[0:[2 4] 1:[1 3 5]]
func Head[T any](values []T) (T, error)

Head returns the first item from values. If values contains no items, it returns the zero value for the type and a IndexOutOfRangeErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	h, err := list.Head([]int{1, 2, 3})
	if err != nil {
		panic(err)
	}
	fmt.Println(h)
}
Output:

1

func IndexBy

func IndexBy[T any](search func(T) bool, values []T) int

IndexBy returns the first index within values that matches the search predicate. If no values match search, it returns -1.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []string{"a", "bb", "ccc"}
	r := list.IndexBy(func(s string) bool { return len(s) <= 2 }, input)
	fmt.Println(r)
}
Output:

0

func IndexByBack

func IndexByBack[T any](search func(T) bool, values []T) int

IndexByBack returns the last index within values that matches the search predicate. If no values match search, it returns -1.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []string{"a", "bb", "ccc"}
	r := list.IndexByBack(func(s string) bool { return len(s) <= 2 }, input)
	fmt.Println(r)
}
Output:

1

func IndexOf

func IndexOf[T comparable](search T, values []T) int

IndexOf returns the first index within values of search. If search is not in values, it returns -1.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []string{"a", "b", "c"}
	r := list.IndexOf("b", input)
	fmt.Println(r)
}
Output:

1
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []string{"a", "b", "c"}
	r := list.IndexOf("d", input)
	fmt.Println(r)
}
Output:

-1

func IndexOfBack

func IndexOfBack[T comparable](search T, input []T) int

IndexOfBack returns the last index within values of search. If search is not in values, it returns -1.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3, 1}
	r := list.IndexOfBack(1, input)
	fmt.Println(r)
}
Output:

3

func Indexed

func Indexed[T any](values []T) []Pair[int, T]

Indexed converts values into Pairs of each value with its index.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []string{"a", "b", "c"}
	r := list.Indexed(input)
	fmt.Println(r)
}
Output:

[(0, "a") (1, "b") (2, "c")]

func InitSlice

func InitSlice[T any, TCount, TIndex constraints.Integer](length TCount, initializer func(TIndex) T) []T

InitSlice makes a new slice of the given length and initializes the values with the return value of initializer when given the index of the item.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.InitSlice(4, func(i int) int { return i + 5 })
	fmt.Println(r)
}
Output:

[5 6 7 8]

func InitSlice2D

func InitSlice2D[T any](initializer func(int, int) T, length1, length2 int) [][]T

InitSlice2D makes a new two dimensional slice of length1 for the first dimension and length2 for the second and initializes the values with the return value of initializer when given the indexes of the item.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.InitSlice2D(func(i, j int) int { return i + j }, 2, 3)
	fmt.Println(r)
}
Output:

[[0 1 2] [1 2 3]]

func InitSlice3D

func InitSlice3D[T any](initializer func(int, int, int) T, length1, length2, length3 int) [][][]T

InitSlice3D makes a new three dimensional slice of length1 for the first dimension, length2 for the second, and length3 for the third and initializes the values with the return value of initializer when given the indexes of the item.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.InitSlice3D(func(i, j, k int) int { return 100*i + 10*j + k }, 2, 2, 3)
	fmt.Println(r)
}
Output:

[[[0 1 2] [10 11 12]] [[100 101 102] [110 111 112]]]

func InitSlice4D

func InitSlice4D[T any](initializer func(int, int, int, int) T, length1, length2, length3, length4 int) [][][][]T

InitSlice4D makes a new four dimensional slice of length1 for the first dimension, length2 for the second, length3 for the third, and length4 for the fourth and initializes the values with the return value of initializer when given the indexes of the item.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.InitSlice4D(func(i, j, k, l int) int { return 1000*i + 100*j + 10*k + l }, 2, 2, 2, 2)
	fmt.Println(r)
}
Output:

[[[[0 1] [10 11]] [[100 101] [110 111]]] [[[1000 1001] [1010 1011]] [[1100 1101] [1110 1111]]]]

func InsertAt

func InsertAt[T any](index int, newValue T, existing []T) ([]T, error)

InsertAt inserts newValue into existing at the given index. If the index is not in the range of indexes for values, it will return a nil slice and a IndexOutOfRangeErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3}
	r, err := list.InsertAt(2, 4, input)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

[0 1 4 2 3]

func InsertManyAt

func InsertManyAt[T any](index int, newValues []T, existing []T) ([]T, error)

InsertManyAt inserts newValues into existing at the given index. If the index is not in the range of indexes for existing, it will return a nil slice and a IndexOutOfRangeErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3}
	r, err := list.InsertManyAt(2, []int{4, 5, 6}, input)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

[0 1 4 5 6 2 3]

func IsEmpty

func IsEmpty[T any](values []T) bool

IsEmpty tests if the slice of values is empty.

func Item

func Item[T any](index int, values []T) (T, error)

Item is the same as values[index] but instead of a panic it returns a IndexOutOfRangeErr if index is outside of the range of indexes in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3, 4}
	r, err := list.Item(2, input)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

2

func Item2D

func Item2D[T any](values [][]T, index1, index2 int) (T, error)

Item2D is the same as values[index1][index2] but instead of a panic it returns a IndexOutOfRangeErr if index is outside of the range of indexes in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][]int{{0, 1}, {2, 3, 4}}
	r, err := list.Item2D(input, 1, 2)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

4

func Item3D

func Item3D[T any](values [][][]T, index1, index2, index3 int) (T, error)

Item3D is the same as values[index1][index2][index3] but instead of a panic it returns a IndexOutOfRangeErr if index is outside of the range of indexes in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][][]int{{}, {{0, 1}, {2, 3, 4}}}
	r, err := list.Item3D(input, 1, 1, 1)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

3

func Item4D

func Item4D[T any](values [][][][]T, index1, index2, index3, index4 int) (T, error)

Item4D is the same as values[index1][index2][index3][index4] but instead of a panic it returns a IndexOutOfRangeErr if index is outside of the range of indexes in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][][][]int{{}, {{}, {{}, {0, 1}, {2, 3, 4}}}}
	r, err := list.Item4D(input, 1, 1, 2, 1)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

3

func Iter

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

Iter iterates over the values, applying action to each value.

Example
input := []string{"0", "1", "2", "3", "4", "5"}
var r string
list.Iter(func(s string) { r += s }, input)
fmt.Println(r)
Output:

012345

func Iter2

func Iter2[T, T2 any](action func(T, T2), values1 []T, values2 []T2)

Iter2 iterates over two slices of values, applying action to each pair of values. It only iterates until the end of the shortest of the value slices.

Example
input1 := []string{"hello", "hi", "howdy"}
input2 := []string{"john", "mary", "tim", "larry"}
var r string
list.Iter2(func(t1, t2 string) { r += t1 + " " + t2 + ", " }, input1, input2)
fmt.Println(r)
Output:

hello john, hi mary, howdy tim,

func Iter2D

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

Iter2D iterates over a two dimensional slice of values, applying action to each value.

Example
input := [][]int{{1, 2}, {3, 4}, {5}}
var r string
list.Iter2D(func(t int) { r += strconv.Itoa(t) }, input)
fmt.Println(r)
Output:

12345

func Iter2DRev

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

Iter2DRev iterates over a two dimensional slice of values in reverse, applying action to each value.

func Iter2Rev

func Iter2Rev[T, T2 any](action func(T, T2), values1 []T, values2 []T2)

Iter2Rev iterates over two slices of values in reverse, applying action to each pair of values. It only iterates until the end of the shortest of the value slices.

func Iter3

func Iter3[T, T2, T3 any](action func(T, T2, T3), values1 []T, values2 []T2, values3 []T3)

Iter3 iterates over three slices of values, applying action to each series of values. It only iterates until the end of the shortest of the value slices.

Example
input1 := []string{"hello", "hi", "howdy"}
input2 := []string{"john", "mary", "tim", "larry"}
input3 := []string{"dunn", "contrary", "tam"}
var r string
list.Iter3(func(t1, t2, t3 string) { r += t1 + " " + t2 + " " + t3 + ", " }, input1, input2, input3)
fmt.Println(r)
Output:

hello john dunn, hi mary contrary, howdy tim tam,

func Iter3D

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

Iter3D iterates over a three dimensional slice of values, applying action to each value.

Example
input := [][][]int{{{1, 2}, {3, 4}}, {{5}}}
var r string
list.Iter3D(func(t int) { r += fmt.Sprintf("%d", t) }, input)
fmt.Println(r)
Output:

12345

func Iter3DRev

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

Iter3DRev iterates over a three dimensional slice of values in reverse, applying action to each value.

func Iter3Rev

func Iter3Rev[T, T2, T3 any](action func(T, T2, T3), values1 []T, values2 []T2, values3 []T3)

Iter3Rev iterates over three slices of values in reverse, applying action to each series of values. It only iterates until the end of the shortest of the value slices.

func Iter4D

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

Iter4D iterates over a four dimensional slice of values, applying action to each value.

func Iter4DRev

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

Iter4DRev iterates over a four dimensional slice of values in reverse, applying action to each value.

func IterRev

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

IterRev iterates over the values in reverse, applying action to each value.

Example
input := []int{0, 1, 2, 3, 4}
var s string
list.IterRev(func(t int) { s += strconv.Itoa(t) }, input)
fmt.Println(s)
Output:

43210

func IterRevUntil

func IterRevUntil[T any](action func(T) bool, values []T)

IterRevUntil iterates over a slice of values in reverse, applying action to each value until action returns true.

func IterUntil

func IterUntil[T any](action func(T) bool, values []T)

IterUntil iterates over a slice of values, applying action to each value until action returns true.

func Iteri

func Iteri[T any](action func(int, T), values []T)

Iteri iterates over the values, applying action to each value with the index of the value.

Example
input := []string{"5", "4", "3", "2", "1", "0"}
var r string
list.Iteri(func(i int, s string) { r += strconv.Itoa(i) + s }, input)
fmt.Println(r)
Output:

051423324150

func Iteri2

func Iteri2[T, T2 any](action func(int, T, T2), values1 []T, values2 []T2)

Iteri2 iterates over the two slices of values, applying action to each pair of values with the index of the values. It only iterates until the end of the shortest of the value slices.

Example
input1 := []string{"hello", "hi", "howdy"}
input2 := []string{"john", "mary", "tim", "larry"}
var r string
list.Iteri2(func(i int, t1, t2 string) { r += t1 + " " + t2 + IfV(i == len(input1)-1, "").Else(", ") }, input1, input2)
fmt.Println(r)
Output:

hello john, hi mary, howdy tim

func Iteri2D

func Iteri2D[T any](action func(int, int, T), values [][]T)

Iteri2D iterates over a two dimensional slice of values, applying action to each value with the indexes of the value.

Example
input := [][]int{{1, 2}, {3, 4}, {5}}
var r string
list.Iteri2D(func(i int, j int, t int) { r += fmt.Sprintf("(%d, %d):%d ", i, j, t) }, input)
fmt.Println(r)
Output:

(0, 0):1 (0, 1):2 (1, 0):3 (1, 1):4 (2, 0):5

func Iteri2DRev

func Iteri2DRev[T any](action func(int, int, T), values [][]T)

Iteri2DRev iterates over a two dimensional slice of values in reverse, applying action to each value with the indexes of the value.

func Iteri2Rev

func Iteri2Rev[T, T2 any](action func(int, T, T2), values1 []T, values2 []T2)

Iteri2Rev iterates over the two slices of values in reverse, applying action to each pair of values with the index of the values. It only iterates until the end of the shortest of the value slices.

func Iteri3

func Iteri3[T, T2, T3 any](action func(int, T, T2, T3), values1 []T, values2 []T2, values3 []T3)

Iteri3 iterates over the three slices of values, applying action to each series of values with the index of the values. It only iterates until the end of the shortest of the value slices.

Example
input1 := []string{"hello", "hi", "howdy"}
input2 := []string{"john", "mary", "tim", "larry"}
input3 := []string{"dunn", "contrary", "tam"}
var r string
list.Iteri3(func(i int, t1, t2, t3 string) {
	r += t1 + " " + t2 + " " + t3 + IfV(i == list.LastIndexOf(input1), "").Else(", ")
}, input1, input2, input3)
fmt.Println(r)
Output:

hello john dunn, hi mary contrary, howdy tim tam

func Iteri3D

func Iteri3D[T any](action func(int, int, int, T), values [][][]T)

Iteri3D iterates over a three dimensional slice of values, applying action to each value with the indexes of each value.

Example
input := [][][]int{{{1, 2}, {3, 4}}, {{5}}}
var r string
list.Iteri3D(func(i int, j int, k int, t int) { r += fmt.Sprintf("(%d, %d, %d):%d ", i, j, k, t) }, input)
fmt.Println(r)
Output:

(0, 0, 0):1 (0, 0, 1):2 (0, 1, 0):3 (0, 1, 1):4 (1, 0, 0):5

func Iteri3DRev

func Iteri3DRev[T any](action func(int, int, int, T), values [][][]T)

Iteri3DRev iterates over a three dimensional slice of values in reverse, applying action to each value with the indexes of each value.

func Iteri3Rev

func Iteri3Rev[T, T2, T3 any](action func(int, T, T2, T3), values1 []T, values2 []T2, values3 []T3)

Iteri3Rev iterates over the three slices of values in reverse, applying action to each series of values with the index of the values. It only iterates until the end of the shortest of the value slices.

func Iteri4D

func Iteri4D[T any](action func(int, int, int, int, T), values [][][][]T)

Iteri4D iterates over a four dimensional slice of values, applying action to each value with the indexes of each value.

func Iteri4DRev

func Iteri4DRev[T any](action func(int, int, int, int, T), values [][][][]T)

Iteri4DRev iterates over a four dimensional slice of values in reverse, applying action to each value with the indexes of each value.

func IteriRev

func IteriRev[T any](action func(int, T), values []T)

IteriRev iterates over the values in reverse, applying action to each value with the index of the value.

Example
input := []int{0, 1, 2, 3, 4}
var s string
list.IteriRev(func(i, t int) { s += fmt.Sprintf("%d:%d,", i, t) }, input)
fmt.Println(s)
Output:

4:4,3:3,2:2,1:1,0:0,

func Last

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

Last returns the last item from values. If values contains no items, it returns the zero value for the type and a IndexOutOfRangeErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	l, err := list.Last([]int{1, 2, 3})
	if err != nil {
		panic(err)
	}
	fmt.Println(l)
}
Output:

3

func LastIndexOf

func LastIndexOf[T any](values []T) int

LastIndexOf is just a replacement for len(values) - 1.

func Len2

func Len2[T any](values [][]T) int

Len2 gets the minimum length of the sub slices in the two dimensional slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][]int{{1, 2, 3}, {1, 2, 3}, {1, 2, 3, 4}, {1, 2, 3}}
	r := list.Len2(input)
	fmt.Println(r)
}
Output:

3

func Len3

func Len3[T any](values [][][]T) int

Len3 gets the minimum length of the sub slices in the three dimensional slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][][]int{{{1, 2, 3}, {1, 2, 3}}, {{1, 2, 3, 4}}}
	r := list.Len3(input)
	fmt.Println(r)
}
Output:

3

func Len4

func Len4[T any](values [][][][]T) int

Len4 gets the minimum length of the sub slices in the four dimensional slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][][][]int{{{{1, 2, 3}, {1, 2, 3}}}, {{{1, 2, 3, 4}}}}
	r := list.Len4(input)
	fmt.Println(r)
}
Output:

3

func LessThan

func LessThan[T constraints.Ordered](a T) func(T) bool

LessThan returns a function that tests whether the value passed the returned function is less than a. The primary purpose of this function is for use in ForAll or other predicates.

func LessThan2

func LessThan2[T constraints.Ordered](a, b T) bool

LessThan2 tests whether b is less than a. The primary purpose of this function is for use in ForAll2 or other predicates that accept two parameters.

func Map

func Map[T, R any](mapping func(T) R, values []T) []R

Map applies mapping to values and returns the results as a new slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []string{"a", "bb", "ccc"}
	r := list.Map(func(s string) int { return len(s) }, input)
	fmt.Println(r)
}
Output:

[1 2 3]

func Map2

func Map2[T, T2, R any](mapping func(T, T2) R, values1 []T, values2 []T2) []R

Map2 applies mapping to pairs of values from the two slices and returns the results as a new slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []string{"a", "bb", "ccc"}
	input2 := []string{"dddd", "eeeee", "ffffff"}
	r := list.Map2(func(a, b string) int { return len(a) + len(b) }, input1, input2)
	fmt.Println(r)
}
Output:

[5 7 9]

func Map2D

func Map2D[T, R any](mapping func(T) R, values [][]T) [][]R

Map2D applies mapping to each value in the two dimensional slice and returns the results as a new two dimensional slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][]string{{"a", "bb"}, {"ccc"}}
	r := list.Map2D(func(s string) int { return len(s) }, input)
	fmt.Println(r)
}
Output:

[[1 2] [3]]

func Map3

func Map3[T, T2, T3, R any](action func(T, T2, T3) R, values1 []T, values2 []T2, values3 []T3) []R

Map3 applies mapping to three values from the three slices and returns the results as a new slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []string{"a", "bb", "ccc"}
	input2 := []string{"dddd", "eeeee", "ffffff"}
	input3 := []string{"A", "B", "C"}
	r := list.Map3(func(a, b, c string) string { return fmt.Sprintf("%s: %d", c, len(a)+len(b)) }, input1, input2, input3)
	fmt.Println(r)
}
Output:

[A: 5 B: 7 C: 9]

func Map3D

func Map3D[T, R any](mapping func(T) R, values [][][]T) [][][]R

Map3D applies mapping to each value in the three dimensional slice and returns the results as a new three dimensional slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][][]string{{{"a", "bb"}, {"ccc"}}, {{"dddd"}}}
	r := list.Map3D(func(s string) int { return len(s) }, input)
	fmt.Println(r)
}
Output:

[[[1 2] [3]] [[4]]]

func MapFold

func MapFold[T any, State any, R any](mapping func(State, T) (R, State), initial State, input []T) ([]R, State)

MapFold combines map and fold. Builds a new list whose elements are the results of applying the given function to each of the elements of the input list. The function is also used to accumulate a final value.

Example
type Charge struct {
	Type  ChargeType
	Value int
}
input := []Charge{{Type: In, Value: 1}, {Type: Out, Value: 2}, {Type: In, Value: 3}}
r, s := list.MapFold(func(acc int, charge Charge) (Charge, int) {
	val := charge.Value
	charge.Value *= 2
	if charge.Type == In {
		return charge, acc + val
	} else {
		return charge, acc - val
	}
}, 0, input)
fmt.Println(r, s)
Output:

[{In 2} {Out 4} {In 6}] 2

func MapFoldBack

func MapFoldBack[T any, State any, R any](mapping func(State, T) (R, State), initial State, input []T) ([]R, State)

MapFoldBack combines map and foldBack. Builds a new list whose elements are the results of applying the given function to each of the elements of the input list in reverse. The function is also used to accumulate a final value.

Example
type Charge struct {
	Type  ChargeType
	Value int
}
input := []Charge{{Type: In, Value: 1}, {Type: Out, Value: 2}, {Type: In, Value: 3}}
r, s := list.MapFoldBack(func(acc int, charge Charge) (Charge, int) {
	val := charge.Value
	charge.Value *= 2
	if charge.Type == In {
		return charge, acc + val
	} else {
		return charge, acc - val
	}
}, 0, input)
fmt.Println(r, s)
Output:

[{In 6} {Out 4} {In 2}] 2

func Mapi

func Mapi[T, R any](mapping func(int, T) R, values []T) []R

Mapi applies mapping to values with the index of each value and returns the results as a new slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []string{"a", "bb", "ccc"}
	r := list.Mapi(func(i int, s string) int { return i * len(s) }, input)
	fmt.Println(r)
}
Output:

[0 2 6]

func Mapi2

func Mapi2[T, T2, R any](mapping func(int, T, T2) R, values1 []T, values2 []T2) []R

Mapi2 applies mapping to pairs of values with the index of each value from the two slices and returns the results as a new slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []string{"a", "bb", "ccc"}
	input2 := []string{"dddd", "eeeee", "ffffff"}
	r := list.Mapi2(func(i int, a, b string) int { return i * (len(a) + len(b)) }, input1, input2)
	fmt.Println(r)
}
Output:

[0 7 18]

func Mapi2D

func Mapi2D[T, R any](mapping func(int, int, T) R, values [][]T) [][]R

Mapi2D applies mapping to each value in the two dimensional slice with the indexes and returns the results as a new two dimensional slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][]string{{"a", "bb"}, {"ccc"}}
	r := list.Mapi2D(func(i, j int, s string) int { return i + j + len(s) }, input)
	fmt.Println(r)
}
Output:

[[1 3] [4]]

func Mapi3

func Mapi3[T, T2, T3, R any](mapping func(int, T, T2, T3) R, values1 []T, values2 []T2, values3 []T3) []R

Mapi3 applies mapping to three values with the index of each value from the three slices and returns the results as a new slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []string{"a", "bb", "ccc"}
	input2 := []string{"dddd", "eeeee", "ffffff"}
	input3 := []string{"A", "B", "C"}
	r := list.Mapi3(func(i int, a, b, c string) string { return fmt.Sprintf("%d-%s: %d", i, c, len(a)+len(b)) }, input1, input2, input3)
	fmt.Println(r)
}
Output:

[0-A: 5 1-B: 7 2-C: 9]

func Mapi3D

func Mapi3D[T, R any](mapping func(int, int, int, T) R, values [][][]T) [][][]R

Mapi3D applies mapping to each value in the three dimensional slice with the indexes and returns the results as a new three dimensional slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := [][][]string{{{"a", "bb"}, {"ccc"}}, {{"dddd"}}}
	r := list.Mapi3D(func(i, j, k int, s string) int { return i + j + k + len(s) }, input)
	fmt.Println(r)
}
Output:

[[[1 3] [4]] [[5]]]

func Max

func Max[T constraints.Ordered](values ...T) (T, error)

Max finds the maximum value in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	max, err := list.Max(1, 2, 3, -1)
	if err != nil {
		panic(err)
	}
	fmt.Println(max)
}
Output:

3

func MaxBy

func MaxBy[T any, T2 constraints.Ordered](projection func(T) T2, values ...T) (T, error)

MaxBy returns the maximum projection(value) in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	max, err := list.MaxBy(func(s string) int { return len(s) }, "short", "longest")
	if err != nil {
		panic(err)
	}
	fmt.Println(max)
}
Output:

longest

func Min

func Min[T constraints.Ordered](values ...T) (T, error)

Min finds the minimum value in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	min, err := list.Min(1, 2, 3, -1)
	if err != nil {
		panic(err)
	}
	fmt.Println(min)
}
Output:

-1

func MinBy

func MinBy[T any, T2 constraints.Ordered](projection func(T) T2, values ...T) (T, error)

MinBy returns the minimum projection(value) in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	min, err := list.MinBy(func(s string) int { return len(s) }, "short", "longest")
	if err != nil {
		panic(err)
	}
	fmt.Println(min)
}
Output:

short

func MinLen

func MinLen[T any](values ...[]T) int

MinLen returns the minimum length of the slices.

func MinSlice

func MinSlice[T any](values ...[]T) []T

MinSlice returns the first slice within values that has the minimum length.

func MustHead

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

MustHead returns the first item from values. If values contains no items, it will panic with an index out of range. This should only be used when you are certain there is at least one item in values.

func MustLast

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

MustLast returns the last item from values. If values contains no items, it will panic with an index out of range. This should only be used when you are certain there is at least one item in values.

func MustMax

func MustMax[T constraints.Ordered](values ...T) T

MustMax is the same as Max but panics instead of returning an error.

func MustMaxBy

func MustMaxBy[T any, T2 constraints.Ordered](projection func(T) T2, values ...T) T

MustMaxBy is the same as MaxBy but panics instead of returning an error.

func MustMin

func MustMin[T constraints.Ordered](values ...T) T

MustMin is the same as Min but panics instead of returning an error.

func MustMinBy

func MustMinBy[T any, T2 constraints.Ordered](projection func(T) T2, values ...T) T

MustMinBy is the same as MinBy but panics instead of returning an error.

func Not

func Not[T comparable](predicate func(T) bool) func(T) bool

Not returns a function that tests for the negative of the predicate. The primary purpose of this function is for use in ForAll or other predicates.

func Not2

func Not2[T, T2 comparable](predicate func(T, T2) bool) func(T, T2) bool

Not2 returns a function that tests for the negative of the two-parameter predicate. The primary purpose of this function is for use in ForAll2 or other predicates that accept two parameters.

func Pairwise

func Pairwise[T any](input []T) []Pair[T, T]

Pairwise returns a slice of each item in the input slice and the one before it, except for the first item which is only returned as the one before the second element.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3, 4, 5}
	r := list.Pairwise(input)
	fmt.Println(r)
}
Output:

[(1, 2) (2, 3) (3, 4) (4, 5)]

func Partition

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

Partition splits the slice into two slices. The first slice contains the items for which the given predicate returns True, and the second slice contains the items for which the given predicate returns False respectively.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3, 4}
	t, f := list.Partition(func(i int) bool { return i%2 == 0 }, input)
	fmt.Println(t, f)
}
Output:

[2 4] [1 3]

func Permute

func Permute[T any](indexMap func(int) int, values []T) []T

Permute returns a slice with all items rearranged by the indexMap function.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3, 4}
	r := list.Permute(func(i int) int { return (i + 1) % 4 }, input)
	fmt.Println(r)
}
Output:

[4 1 2 3]

func Pick

func Pick[T any, R any](chooser func(T) option.Option[R], values []T) (R, error)

Pick applies chooser to each value in values until chooser returns Some. It then returns the value within Some. If no values are matched by chooser, a NotFoundErr is returned.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/flowonyx/functional/list"
	"github.com/flowonyx/functional/option"
)

func main() {
	i, err := list.Pick(func(s string) option.Option[int] {
		if i, err := strconv.Atoi(s); err == nil {
			return option.Some(i)
		}
		return option.None[int]()
	}, []string{"zero", "1", "2", "three", "4"})
	if err != nil {
		panic(err)
	}
	fmt.Println(i)
}
Output:

1

func Range

func Range[TInt constraints.Integer](start, end TInt, step ...int) []TInt

Range creates a slice of Integers from start to end. If step is specified, the values will be spaced by that amount.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Range(0, 10)
	fmt.Println(r)
}
Output:

[0 1 2 3 4 5 6 7 8 9 10]
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Range(10, 0)
	fmt.Println(r)
}
Output:

[10 9 8 7 6 5 4 3 2 1 0]
Example (Third)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Range(10, 0, 2)
	fmt.Println(r)
}
Output:

[10 8 6 4 2 0]

func RangeChan

func RangeChan[TInt constraints.Integer](start, end TInt, step ...int) <-chan TInt

RangeChan creates a chan of Integers that it sends values form start to end. If step is specified, the values will be spaced by that amount.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.RangeChan(0, 10)
	var s []int
	for i := range r {
		s = append(s, i)
	}
	fmt.Println(s)
}
Output:

[0 1 2 3 4 5 6 7 8 9 10]

func RangeTo

func RangeTo[TInt constraints.Integer](end TInt) []TInt

RangeTo creates a slice of Integers from 0 to end.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.RangeTo(8)
	fmt.Println(r)
}
Output:

[0 1 2 3 4 5 6 7 8]

func Reduce

func Reduce[T any, R any](inital R, f func(accumulator R, each T) R, values []T) R

Reduce applies f to each value in values, threading an accumulator argument through the computation. Apply the function to the first two elements of the list. Then feed this result into the function along with the third element and so on. Return the final result.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 3, 4, 2}
	r := list.Reduce(0, func(a, b int) int { return a*10 + b }, input)
	fmt.Println(r)
}
Output:

1342

func ReduceBack

func ReduceBack[T any](initial T, f func(accumulator T, each T) T, values []T) T

ReduceBack applies f to each value in values in reverse, threading an accumulator argument through the computation. Apply the function to the first two elements of the list. Then feed this result into the function along with the third element and so on. Return the final result.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 3, 4, 2}
	r := list.ReduceBack(0, func(a, b int) int { return a*10 + b }, input)
	fmt.Println(r)
}
Output:

2431

func RemoveAt

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

RemoveAt removes the item at index from values. If index is not in the range of indexes for values, it will return a nil slice and a IndexOutOfRangeErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3}
	r, err := list.RemoveAt(2, input)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

[0 1 3]
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3}
	r, err := list.RemoveAt(3, input)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

[0 1 2]

func RemoveManyAt

func RemoveManyAt[T any](index int, count int, values []T) ([]T, error)

RemoveManyAt removes count number of items starting at index from values. If index is not in the range of indexes for values, it will return a nil slice and a IndexOutOfRangeErr. If count is larger the the number of items in values starting at index, it will only remove as many items as is in the slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3}
	r, err := list.RemoveManyAt(2, 5, input)
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}
Output:

[0 1]

func Reverse

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

Reverse returns a clone of a slice with values in reverse order.

Example
input := []int{3, 2, 5, 8, 1}
r := list.Reverse(input)
fmt.Println(r)
Output:

[1 8 5 2 3]

func Scan

func Scan[State any, T any](folder func(State, T) State, initialState State, values []T) []State

Scan applies a function to each element of the collection, threading an accumulator argument through the computation. Take the second argument, and apply the function to it and the first element of the list. Then feed this result into the function along with the second element and so on. Returns the list of intermediate results and the final result.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3}
	r := list.Scan(func(s int, t int) int {
		return s + t
	}, 0, input)
	fmt.Println(r)
}
Output:

[0 1 3 6]

func ScanBack

func ScanBack[State any, T any](folder func(State, T) State, initialState State, values []T) []State

ScanBack applies a function to each element of the collection in reverse, threading an accumulator argument through the computation. Take the second argument, and apply the function to it and the first element of the list. Then feed this result into the function along with the second element and so on. Returns the list of intermediate results and the final result.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3}
	r := list.ScanBack(func(s int, t int) int {
		return s + t
	}, 0, input)
	fmt.Println(r)
}
Output:

[0 3 5 6]

func SetItem

func SetItem[T any](values []T, index int, value T) error

SetItem sets values[index] to value or returns an IndexOutOfRange error if the index is outside the range of indexes in values.

func SetItem2D

func SetItem2D[T any](values [][]T, index1, index2 int, value T) error

SetItem2D sets values[index1][index2] to value or returns an IndexOutOfRange error if any of the indexes is outside the range of indexes in values.

func SetItem3D

func SetItem3D[T any](values [][][]T, index1, index2, index3 int, value T) error

func SetItem4D

func SetItem4D[T any](values [][][][]T, index1, index2, index3, index4 int, value T) error

func Singleton

func Singleton[T any](value T) []T

Singleton creates a slice with one value.

func Skip

func Skip[T any](count int, values []T) []T

Skip returns a clone of values starting from count. It is the same as values[count:] but returns it as a clone so that modifications to the returned slice do not affect to original slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3, 4, 5}
	r := list.Skip(2, input)
	fmt.Println(r)
}
Output:

[3 4 5]

func SkipWhile

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

SkipWhile returns a clone of values starting from where predicate returns false. If predicate never returns false, it returns an empty slice. The returned slice is a clone, so modifications to it do not affect the original slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3, 4, 5}
	r := list.SkipWhile(list.LessThan(3), input)
	fmt.Println(r)
}
Output:

[3 4 5]

func Sort

func Sort[T constraints.Ordered](values []T) []T

Sort returns a clone of a slice of any ordered type sorted in ascending order.

Example
input := []int{3, 2, 5, 8, 1}
r := list.Sort(input)
fmt.Println(r)
Output:

[1 2 3 5 8]

func SortBy

func SortBy[T any, Key constraints.Ordered](projection func(T) Key, values []T) []T

SortBy returns a clone of a slice of any type sorted in ascending order based on the key returned from projection.

Example
input := []int{3, 2, 5, 8, 1}
r := list.SortBy(func(i int) int {
	return IfV(i < 5, i*10).Else(i)
}, input)
fmt.Println(r)
Output:

[5 8 1 2 3]

func SortByDescending

func SortByDescending[T any, Key constraints.Ordered](projection func(T) Key, values []T) []T

SortByDescending returns a clone of a slice of any type sorted in descending order based on the key returned from projection.

Example
input := []int{3, 2, 5, 8, 1}
r := list.SortByDescending(func(i int) int {
	return IfV(i < 5, i*10).Else(i)
}, input)
fmt.Println(r)
Output:

[3 2 1 8 5]

func SortDescending

func SortDescending[T constraints.Ordered](values []T) []T

SortDescending returns a clone of a slice of any ordered type sorted in descending order.

Example
input := []int{3, 2, 5, 8, 1}
r := list.SortDescending(input)
fmt.Println(r)
Output:

[8 5 3 2 1]

func SortWith

func SortWith[T any](less func(T, T) int, values []T) []T

SortWith returns a clone of a slice of any type sorted in order as determined by the less function. This sort is not guaranteed to be stable.

Example
input := []int{3, 2, 5, 8, 1}
r := list.SortWith(func(t1, t2 int) int {
	if t1 > t2 {
		return -1
	}
	if t2 > t1 {
		return 1
	}
	return 0
}, input)
fmt.Println(r)
Output:

[8 5 3 2 1]

func SplitAt

func SplitAt[T any](index int, values []T) ([]T, []T, error)

SpitAt splits values at index into two separate slices. If index is out of range, it will return an IndexOutOfRangeErr.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3, 4, 5}
	a, b, err := list.SplitAt(3, input)
	if err != nil {
		panic(err)
	}
	fmt.Println(a, b)
}
Output:

[0 1 2] [3 4 5]

func SplitInto

func SplitInto[T any](count int, values []T) [][]T

SplitInto splits values into a series of slices of whatever length is necessary to have count slices.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input1 := []int{1}
	input2 := []int{1, 2}
	input3 := []int{1, 2, 3}
	input4 := []int{1, 2, 3, 4}
	input5 := []int{1, 2, 3, 4, 5}
	r := list.SplitInto(3, input1)
	r2 := list.SplitInto(3, input2)
	r3 := list.SplitInto(3, input3)
	r4 := list.SplitInto(3, input4)
	r5 := list.SplitInto(3, input5)
	fmt.Println(r, r2, r3, r4, r5)
}
Output:

[[1]] [[1] [2]] [[1] [2] [3]] [[1] [2] [3 4]] [[1 2] [3 4] [5]]

func Sum

func Sum[T numeric | ~string](values []T) T

Sum returns the result of adding all values together.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Sum([]int{1, 2, 3})
	fmt.Println(r)
}
Output:

6
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Sum([]string{"hello ", "world", "!"})
	fmt.Println(r)
}
Output:

hello world!

func SumBy

func SumBy[T any, R numeric | ~string](projection func(T) R, values []T) R

SumBy returns the result of adding all results of applying projection to each value.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/flowonyx/functional/list"
)

func main() {
	type summ struct {
		val float64
	}
	r := list.SumBy(func(s summ) float64 { return s.val }, []summ{{val: 1.1}, {val: 2.2}})
	fmt.Printf("%s", strconv.FormatFloat(r, 'f', 1, 64))
}
Output:

3.3

func Tail

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

Tail returns all but the first item from values. If values contains no items, it returns the an empty slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	t := list.Tail([]int{1, 2, 3})
	fmt.Println(t)
}
Output:

[2 3]

func Take

func Take[T any](count int, values []T) option.Option[[]T]

Take returns an Option of the first count values in the slice. If count exceeds the number of values in the slice, it returns None. To return all values when count exceeds the number of values, use Truncate.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Take(3, []int{0, 1, 2, 3, 4})
	fmt.Println(r.Value())
}
Output:

[0 1 2]

func TakeWhile

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

TakeWhile returns the the first values in the slice until predicate returns false.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.TakeWhile(func(i int) bool { return i == 0 || i%2 != 0 }, []int{0, 1, 2, 3, 4})
	fmt.Println(r)
}
Output:

[0 1]

func Transpose

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

Transpose returns the transpose of the sequence of slices.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Transpose([][]int{{10, 20, 30}, {11, 21, 31}})
	fmt.Println(r)
}
Output:

[[10 11] [20 21] [30 31]]

func Truncate

func Truncate[T any](count int, values []T) []T

Truncate returns the first count values in the slie. If count exceeds the number of values in the slice, it will return all values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	r := list.Truncate(3, []int{0, 1, 2, 3, 4})
	fmt.Println(r)
}
Output:

[0 1 2]

func TryExactlyOne

func TryExactlyOne[T any](input []T) option.Option[T]

TryExactlyOne returns the single item in a slice as an Option. If the slice is empty or has more than one item it will return None.

func TryFind

func TryFind[T any](predicate func(T) bool, values ...T) option.Option[T]

TryFind returns an Option of the first value that matches predicate. If no values match predicate, it returns None.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func mod2(i int) bool { return i%2 == 0 }

func main() {
	r := list.TryFind(mod2, 1, 2, 3, 4)
	if r.IsNone() {
		panic("TryFind should have found 2")
	}
	fmt.Println(r.Value())
}
Output:

2

func TryFindBack

func TryFindBack[T any](predicate func(T) bool, values ...T) option.Option[T]

TryFindBack returns an Option of the last value that matches predicate. If no values match predicate, it returns None.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func mod2(i int) bool { return i%2 == 0 }

func main() {
	r := list.TryFindBack(mod2, 1, 2, 3, 4)
	if r.IsNone() {
		panic("TryFind should have found 4")
	}
	fmt.Println(r.Value())
}
Output:

4

func TryHead

func TryHead[T any](values []T) option.Option[T]

TryHead returns the first item from values as an Option. If values contains no items, it returns None.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	h := list.TryHead([]int{1, 2, 3})
	fmt.Println(h.Value())
}
Output:

1

func TryIndexBy

func TryIndexBy[T any](search func(T) bool, input []T) option.Option[int]

TryIndexBy returns the first index within values that matches the search predicate as an Option. If search is not in values, it returns None. This function is probably only useful if you working heavily with Options.

func TryIndexByBack

func TryIndexByBack[T any](search func(T) bool, input []T) option.Option[int]

TryIndexByBack returns the last index within values that matches the search predicate as an Option. If search is not in values, it returns None. This function is probably only useful if you working heavily with Options.

func TryIndexOf

func TryIndexOf[T comparable](search T, input []T) option.Option[int]

TryIndexOf returns the first index within values of search as an Option. If search is not in values, it returns None. This function is probably only useful if you working heavily with Options.

func TryIndexOfBack

func TryIndexOfBack[T comparable](search T, input []T) option.Option[int]

TryIndexOfBack returns the last index within values of search as an Option. If search is not in values, it returns None. This function is probably only useful if you working heavily with Options.

func TryItem

func TryItem[T any](index int, values []T) option.Option[T]

TryItem is the same as Some(values[index]) but instead of a panic it returns None if index is outside of the range of indexes in values.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3, 4}
	r := list.TryItem(2, input)
	fmt.Println(r.Value())
}
Output:

2
Example (Second)
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{0, 1, 2, 3, 4}
	r := list.TryItem(5, input)
	fmt.Println(r.IsNone())
}
Output:

true

func TryItem2D

func TryItem2D[T any](values [][]T, index1, index2 int) option.Option[T]

TryItem2D is the same as Some(values[index1][index2]) but instead of a panic it returns None if index is outside of the range of indexes in values.

func TryItem3D

func TryItem3D[T any](values [][][]T, index1, index2, index3 int) option.Option[T]

TryItem3D is the same as Some(values[index1][index2][index3]) but instead of a panic it returns None if index is outside of the range of indexes in values.

func TryItem4D

func TryItem4D[T any](values [][][][]T, index1, index2, index3, index4 int) option.Option[T]

TryItem4D is the same as Some(values[index1][index2][index3][index4]) but instead of a panic it returns None if index is outside of the range of indexes in values.

func TryLast

func TryLast[T any](values []T) option.Option[T]

TryLast returns the last item from values as an Option. If values contains no items, it returns None.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	l := list.TryLast([]int{1, 2, 3})
	fmt.Println(l.Value())
}
Output:

3

func TryPick

func TryPick[T any, R any](chooser func(T) option.Option[R], values []T) option.Option[R]

TryPick is the same as Pick but returns None in place of an error.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/flowonyx/functional/list"
	"github.com/flowonyx/functional/option"
)

func main() {
	i := list.TryPick(func(s string) option.Option[int] {
		if i, err := strconv.Atoi(s); err == nil {
			return option.Some(i)
		}
		return option.None[int]()
	}, []string{"zero", "1", "2", "three", "4"})

	fmt.Println(i.Value())
}
Output:

1

func Unfold

func Unfold[T any, State any](generator func(State) option.Option[Pair[T, State]], state State) []T

Unfold applies generator to state until generator returns None (or it is run 1000000 times). It returns all the generated values.

Example
r := Unfold(func(s int) option.Option[Pair[int, int]] {
	return IfV(s > 100, option.None[Pair[int, int]]()).
		Else(option.Some(PairOf(s, s*2)))
}, 1)
fmt.Println(r)
Output:

[1 2 4 8 16 32 64]

func Unzip

func Unzip[T, T2 any](values []Pair[T, T2]) ([]T, []T2)

Unzip takes a slice of Pairs and returns a slice of all values in the first position and another slice with all values in the second position.

Example
input := []Pair[int, string]{{1, "one"}, {2, "two"}}
a, b := list.Unzip(input)
fmt.Println(a, b)
Output:

[1 2] [one two]

func Unzip3

func Unzip3[T, T2, T3 any](values []Triple[T, T2, T3]) ([]T, []T2, []T3)

Unzip3 takes a slice of Triples and returns a slice of all values in the first position, another slice with all values in the second position, and another slice with all values in the third position.

Example
input := []Triple[int, string, string]{{1, "one", "I"}, {2, "two", "II"}}
a, b, c := list.Unzip3(input)
fmt.Println(a, b, c)
Output:

[1 2] [one two] [I II]

func UpdateAt

func UpdateAt[T any](index int, value T, values []T) ([]T, error)

func UpdateAt2D

func UpdateAt2D[T any](index1, index2 int, value T, values [][]T) ([][]T, error)

func UpdateAt3D

func UpdateAt3D[T any](index1, index2, index3 int, value T, values [][][]T) ([][][]T, error)

func UpdateAt4D

func UpdateAt4D[T any](index1, index2, index3, index4 int, value T, values [][][][]T) ([][][][]T, error)

func ValueEqual

func ValueEqual[T comparable](a T) func(T) bool

ValueEqual returns a function that tests equality of a with the value passed the returned function. The primary purpose of this function is for use in ForAll or other predicates.

func ValueEqual2

func ValueEqual2[T comparable](a, b T) bool

ValueEqual2 tests equality of a with b. The primary purpose of this function is for use in ForAll2 or other predicates that accept two parameters.

func Windowed

func Windowed[T any](windowSize int, values []T) [][]T

Windowed returns the values in sliding windows of the size specified by windowSize. Each window is returned as a fresh slice.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	input := []int{1, 2, 3, 4, 5}
	r := list.Windowed(3, input)
	fmt.Println(r)
}
Output:

[[1 2 3] [2 3 4] [3 4 5]]

func ZeroCreate2D

func ZeroCreate2D[T any](length1 int, length2 int) [][]T

ZeroCreate2D makes a two dimensional slice of the given lengths.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	a := list.ZeroCreate2D[int](4, 4)
	fmt.Println(a)
}
Output:

[[0 0 0 0] [0 0 0 0] [0 0 0 0] [0 0 0 0]]

func ZeroCreate3D

func ZeroCreate3D[T any](length1, length2, length3 int) [][][]T

ZeroCreate3D makes a three dimensional slice of the given lengths.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	a := list.ZeroCreate3D[int](1, 1, 2)
	fmt.Println(a)
}
Output:

[[[0 0]]]

func ZeroCreate4D

func ZeroCreate4D[T any](length1, length2, length3, length4 int) [][][][]T

ZeroCreate4D makes a four dimensional slice of the given lengths.

Example
package main

import (
	"fmt"

	"github.com/flowonyx/functional/list"
)

func main() {
	a := list.ZeroCreate4D[int](1, 1, 2, 2)
	fmt.Println(a)
}
Output:

[[[[0 0] [0 0]]]]

func Zip

func Zip[T, T2 any](values1 []T, values2 []T2) []Pair[T, T2]

Zip puts the two slices of values into one slice of Pairs. It will only returns as many items as the smallest length of the two slices.

Example
input1 := []int{1, 2}
input2 := []string{"one", "two"}

r := list.Zip(input1, input2)
fmt.Println(r)
Output:

[(1, "one") (2, "two")]

func Zip3

func Zip3[T, T2, T3 any](values1 []T, values2 []T2, values3 []T3) []Triple[T, T2, T3]

Zip3 puts the three slices of values into one slice of Triples. It will only returns as many items as the smallest length of the slices.

Example
input1 := []int{1, 2}
input2 := []string{"one", "two"}
input3 := []string{"I", "II"}

r := list.Zip3(input1, input2, input3)
fmt.Println(r)
Output:

[(1, "one", "I") (2, "two", "II")]

Types

This section is empty.

Jump to

Keyboard shortcuts

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