mirror of
https://github.com/rjNemo/underscore
synced 2026-06-06 02:26:42 +00:00
Chain (#7)
* doc: add docs to chan methods * feat: contains * feat: chain each * feat: every each * feat: find each * feat: chain min/max * feat: chain Some * refactor: chain tests Co-authored-by: Ruidy <rnemausat@newstore.com>
This commit is contained in:
parent
7ddb05602c
commit
2f17af7b5d
3 changed files with 164 additions and 18 deletions
|
|
@ -102,7 +102,7 @@ go test ./...
|
|||
Calling `NewChain` will cause all future method calls to return wrapped objects. When you've finished the computation,
|
||||
call `Value` to retrieve the final value.
|
||||
|
||||
Methods not returning a collection such as `Reduce`, `Every`, `Some`, will break the chain and return `Value` instantly.
|
||||
Methods not returning a slice such as `Reduce`, `Every`, `Some`, will break the chain and return `Value` instantly.
|
||||
|
||||
## Built With
|
||||
|
||||
|
|
|
|||
77
chain.go
77
chain.go
|
|
@ -1,21 +1,90 @@
|
|||
package underscore
|
||||
|
||||
type Chain[T any] struct {
|
||||
import "constraints"
|
||||
|
||||
type Chain[T constraints.Ordered] struct {
|
||||
Value []T
|
||||
}
|
||||
|
||||
func NewChain[T any](value []T) Chain[T] {
|
||||
// NewChain starts a Chain. All future method calls will return Chain structs. When you've finished the computation,
|
||||
// call Value to retrieve the final value.
|
||||
//
|
||||
// Methods not returning a slice such as Reduce, Every, Some, will break the chain and return Value instantly.
|
||||
func NewChain[T constraints.Ordered](value []T) Chain[T] {
|
||||
return Chain[T]{Value: value}
|
||||
}
|
||||
|
||||
// Contains returns true if the value is present in the slice and breaks the Chain.
|
||||
func (c Chain[T]) Contains(value T) bool {
|
||||
return Contains(c.Value, value)
|
||||
}
|
||||
|
||||
// Each iterates over a slice of elements, yielding each in turn to an action function.
|
||||
// Breaks the Chain.
|
||||
func (c Chain[T]) Each(action func(T)) {
|
||||
Each(c.Value, action)
|
||||
}
|
||||
|
||||
// Every 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 Chain.
|
||||
func (c Chain[T]) Every(predicate func(T) bool) bool {
|
||||
return Every(c.Value, predicate)
|
||||
}
|
||||
|
||||
// Filter looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate).
|
||||
func (c Chain[T]) Filter(predicate func(n T) bool) Chain[T] {
|
||||
return Chain[T]{Value: Filter(c.Value, predicate)}
|
||||
}
|
||||
|
||||
// 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 Chain.
|
||||
func (c Chain[T]) Find(predicate func(n T) bool) (T, error) {
|
||||
return Find(c.Value, predicate)
|
||||
}
|
||||
|
||||
// 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 (c Chain[T]) Map(transform func(n T) T) Chain[T] {
|
||||
return Chain[T]{Value: Map(c.Value, transform)}
|
||||
}
|
||||
|
||||
func (c Chain[T]) Reduce(reducer func(n, acc T) T, initialValue T) T {
|
||||
return Reduce(c.Value, reducer, initialValue)
|
||||
// Max returns the maximum value in the slice.
|
||||
// This function can currently only compare numbers reliably.
|
||||
// This function uses operator <.
|
||||
// Breaks the Chain.
|
||||
func (c Chain[T]) Max() T {
|
||||
return Max(c.Value)
|
||||
}
|
||||
|
||||
// Min returns the minimum value in the slice.
|
||||
// This function can currently only compare numbers reliably.
|
||||
// This function uses operator <.
|
||||
// Breaks the Chain.
|
||||
func (c Chain[T]) Min() T {
|
||||
return Min(c.Value)
|
||||
}
|
||||
|
||||
// Partition splits the slice into two slices: one whose elements all satisfy predicate
|
||||
// and one whose elements all do not satisfy predicate.
|
||||
// Breaks the Chain.
|
||||
func (c Chain[T]) Partition(predicate func(T) bool) ([]T, []T) {
|
||||
return Partition(c.Value, predicate)
|
||||
}
|
||||
|
||||
// Reduce combine a list of values into a single value and breaks the Chain.
|
||||
// acc is the initial state, and each successive step of it should be returned by the reduction function.
|
||||
func (c Chain[T]) Reduce(reducer func(n, acc T) T, acc T) T {
|
||||
return Reduce(c.Value, reducer, acc)
|
||||
}
|
||||
|
||||
// Some 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 Chain.
|
||||
func (c Chain[T]) Some(predicate func(T) bool) bool {
|
||||
return Some(c.Value, predicate)
|
||||
}
|
||||
|
|
|
|||
103
chain_test.go
103
chain_test.go
|
|
@ -8,26 +8,103 @@ import (
|
|||
u "github.com/rjNemo/underscore"
|
||||
)
|
||||
|
||||
func TestChain(t *testing.T) {
|
||||
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
isEven := func(n int) bool { return n%2 == 0 }
|
||||
toSquare := func(n int) int { return n * n }
|
||||
sum := func(n, acc int) int { return n + acc }
|
||||
|
||||
func TestChainFilter(t *testing.T) {
|
||||
want := []int{2, 4, 6, 8}
|
||||
assert.Equal(t, want, u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Value)
|
||||
assert.Equal(t,
|
||||
want,
|
||||
u.NewChain(nums).Filter(isEven).Value,
|
||||
)
|
||||
}
|
||||
|
||||
want = []int{4, 16, 36, 64}
|
||||
func TestChainFilterMap(t *testing.T) {
|
||||
want := []int{4, 16, 36, 64}
|
||||
assert.Equal(t,
|
||||
want,
|
||||
u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Value)
|
||||
}
|
||||
|
||||
func TestChainFilterMapReduce(t *testing.T) {
|
||||
want := 120
|
||||
assert.Equal(t,
|
||||
want,
|
||||
u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Reduce(sum, 0))
|
||||
}
|
||||
|
||||
func TestChainFilterMapContains(t *testing.T) {
|
||||
assert.True(t, u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Contains(16))
|
||||
}
|
||||
|
||||
func TestChainFilterMapEach(t *testing.T) {
|
||||
want := []int{5, 17, 37, 65}
|
||||
res := make([]int, 0)
|
||||
u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Each(func(n int) { res = append(res, n+1) })
|
||||
assert.Equal(t, want, res)
|
||||
}
|
||||
|
||||
func TestChainFilterMapEvery(t *testing.T) {
|
||||
assert.True(t, u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Every(func(n int) bool { return n%4 == 0 }))
|
||||
}
|
||||
|
||||
func TestChainFilterMapFind(t *testing.T) {
|
||||
n, err := u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Find(func(n int) bool { return n%4 == 0 })
|
||||
assert.Equal(t, 4, n)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestChainFilterMapMax(t *testing.T) {
|
||||
want := 64
|
||||
assert.Equal(t, want, u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Value)
|
||||
Max())
|
||||
}
|
||||
|
||||
w := 120
|
||||
func TestChainFilterMapMin(t *testing.T) {
|
||||
w := 4
|
||||
assert.Equal(t, w, u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Reduce(sum, 0))
|
||||
Min())
|
||||
}
|
||||
|
||||
func TestChainFilterMapPartition(t *testing.T) {
|
||||
wantLeft := []int{4, 16}
|
||||
wantRight := []int{36, 64}
|
||||
left, right := u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Partition(func(n int) bool { return n < 20 })
|
||||
|
||||
assert.Equal(t, wantLeft, left)
|
||||
assert.Equal(t, wantRight, right)
|
||||
}
|
||||
|
||||
func TestChainFilterMapSome(t *testing.T) {
|
||||
assert.True(t, u.NewChain(nums).
|
||||
Filter(isEven).
|
||||
Map(toSquare).
|
||||
Some(func(n int) bool { return n%64 == 0 }))
|
||||
}
|
||||
|
||||
var nums = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
var isEven = func(n int) bool { return n%2 == 0 }
|
||||
var toSquare = func(n int) int { return n * n }
|
||||
var sum = func(n, acc int) int { return n + acc }
|
||||
|
|
|
|||
Loading…
Reference in a new issue