mirror of
https://github.com/rjNemo/underscore
synced 2026-06-06 02:26:42 +00:00
feat: chain package
This commit is contained in:
parent
2d05b6c518
commit
73ed4021a6
3 changed files with 34 additions and 30 deletions
|
|
@ -102,10 +102,10 @@ go test ./...
|
||||||
|
|
||||||
### Chaining
|
### Chaining
|
||||||
|
|
||||||
Calling `NewChain` will cause all future method calls to return wrapped objects. When you've finished the computation,
|
Calling `chain.Of` will cause all future method calls to return wrapped values. When you've finished the computation,
|
||||||
call `Value` to retrieve the final value.
|
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.
|
Methods not returning a slice such as `Reduce`, `Every`, `Some`, will break the `Chain` and return `Value` instantly.
|
||||||
|
|
||||||
## Built With
|
## Built With
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,44 @@
|
||||||
package underscore
|
package chain
|
||||||
|
|
||||||
import "constraints"
|
import (
|
||||||
|
"constraints"
|
||||||
|
|
||||||
|
u "github.com/rjNemo/underscore"
|
||||||
|
)
|
||||||
|
|
||||||
type Chain[T constraints.Ordered] struct {
|
type Chain[T constraints.Ordered] struct {
|
||||||
Value []T
|
Value []T
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChain starts a Chain. All future method calls will return Chain structs. When you've finished the computation,
|
// Of starts a Chain. All future method calls will return Chain structs. When you've finished the computation,
|
||||||
// call Value to retrieve the final value.
|
// 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.
|
// 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] {
|
func Of[T constraints.Ordered](value []T) Chain[T] {
|
||||||
return Chain[T]{Value: value}
|
return Chain[T]{Value: value}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contains returns true if the value is present in the slice and breaks the Chain.
|
// Contains returns true if the value is present in the slice and breaks the Chain.
|
||||||
func (c Chain[T]) Contains(value T) bool {
|
func (c Chain[T]) Contains(value T) bool {
|
||||||
return Contains(c.Value, value)
|
return u.Contains(c.Value, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each iterates over a slice of elements, yielding each in turn to an action function.
|
// Each iterates over a slice of elements, yielding each in turn to an action function.
|
||||||
// Breaks the Chain.
|
// Breaks the Chain.
|
||||||
func (c Chain[T]) Each(action func(T)) {
|
func (c Chain[T]) Each(action func(T)) {
|
||||||
Each(c.Value, action)
|
u.Each(c.Value, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every returns true if all the values in the slice pass the predicate truth test.
|
// 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.
|
// Short-circuits and stops traversing the slice if a false element is found.
|
||||||
// Breaks the Chain.
|
// Breaks the Chain.
|
||||||
func (c Chain[T]) Every(predicate func(T) bool) bool {
|
func (c Chain[T]) Every(predicate func(T) bool) bool {
|
||||||
return Every(c.Value, predicate)
|
return u.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).
|
// 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] {
|
func (c Chain[T]) Filter(predicate func(n T) bool) Chain[T] {
|
||||||
return Chain[T]{Value: Filter(c.Value, predicate)}
|
return Chain[T]{Value: u.Filter(c.Value, predicate)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find looks through each value in the slice, returning the first one that passes a truth test (predicate),
|
// Find looks through each value in the slice, returning the first one that passes a truth test (predicate),
|
||||||
|
|
@ -42,7 +46,7 @@ func (c Chain[T]) Filter(predicate func(n T) bool) Chain[T] {
|
||||||
// The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice.
|
// The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice.
|
||||||
// Breaks the Chain.
|
// Breaks the Chain.
|
||||||
func (c Chain[T]) Find(predicate func(n T) bool) (T, error) {
|
func (c Chain[T]) Find(predicate func(n T) bool) (T, error) {
|
||||||
return Find(c.Value, predicate)
|
return u.Find(c.Value, predicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map produces a new slice of values by mapping each value in the slice through
|
// Map produces a new slice of values by mapping each value in the slice through
|
||||||
|
|
@ -50,7 +54,7 @@ func (c Chain[T]) Find(predicate func(n T) bool) (T, error) {
|
||||||
//
|
//
|
||||||
// TODO: Move from T to P.
|
// TODO: Move from T to P.
|
||||||
func (c Chain[T]) Map(transform func(n T) T) Chain[T] {
|
func (c Chain[T]) Map(transform func(n T) T) Chain[T] {
|
||||||
return Chain[T]{Value: Map(c.Value, transform)}
|
return Chain[T]{Value: u.Map(c.Value, transform)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Max returns the maximum value in the slice.
|
// Max returns the maximum value in the slice.
|
||||||
|
|
@ -58,7 +62,7 @@ func (c Chain[T]) Map(transform func(n T) T) Chain[T] {
|
||||||
// This function uses operator <.
|
// This function uses operator <.
|
||||||
// Breaks the Chain.
|
// Breaks the Chain.
|
||||||
func (c Chain[T]) Max() T {
|
func (c Chain[T]) Max() T {
|
||||||
return Max(c.Value)
|
return u.Max(c.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Min returns the minimum value in the slice.
|
// Min returns the minimum value in the slice.
|
||||||
|
|
@ -66,25 +70,25 @@ func (c Chain[T]) Max() T {
|
||||||
// This function uses operator <.
|
// This function uses operator <.
|
||||||
// Breaks the Chain.
|
// Breaks the Chain.
|
||||||
func (c Chain[T]) Min() T {
|
func (c Chain[T]) Min() T {
|
||||||
return Min(c.Value)
|
return u.Min(c.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Partition splits the slice into two slices: one whose elements all satisfy predicate
|
// Partition splits the slice into two slices: one whose elements all satisfy predicate
|
||||||
// and one whose elements all do not satisfy predicate.
|
// and one whose elements all do not satisfy predicate.
|
||||||
// Breaks the Chain.
|
// Breaks the Chain.
|
||||||
func (c Chain[T]) Partition(predicate func(T) bool) ([]T, []T) {
|
func (c Chain[T]) Partition(predicate func(T) bool) ([]T, []T) {
|
||||||
return Partition(c.Value, predicate)
|
return u.Partition(c.Value, predicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce combine a list of values into a single value and breaks the Chain.
|
// 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.
|
// 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 {
|
func (c Chain[T]) Reduce(reducer func(n, acc T) T, acc T) T {
|
||||||
return Reduce(c.Value, reducer, acc)
|
return u.Reduce(c.Value, reducer, acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some returns true if any of the values in the slice pass the predicate truth test.
|
// 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.
|
// Short-circuits and stops traversing the slice if a true element is found.
|
||||||
// Breaks the Chain.
|
// Breaks the Chain.
|
||||||
func (c Chain[T]) Some(predicate func(T) bool) bool {
|
func (c Chain[T]) Some(predicate func(T) bool) bool {
|
||||||
return Some(c.Value, predicate)
|
return u.Some(c.Value, predicate)
|
||||||
}
|
}
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
package underscore_test
|
package chain_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
u "github.com/rjNemo/underscore"
|
"github.com/rjNemo/underscore/chain"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChainFilter(t *testing.T) {
|
func TestChainFilter(t *testing.T) {
|
||||||
want := []int{2, 4, 6, 8}
|
want := []int{2, 4, 6, 8}
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
want,
|
want,
|
||||||
u.NewChain(nums).Filter(isEven).Value,
|
chain.Of(nums).Filter(isEven).Value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,7 +20,7 @@ func TestChainFilterMap(t *testing.T) {
|
||||||
want := []int{4, 16, 36, 64}
|
want := []int{4, 16, 36, 64}
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
want,
|
want,
|
||||||
u.NewChain(nums).
|
chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Value)
|
Value)
|
||||||
|
|
@ -30,14 +30,14 @@ func TestChainFilterMapReduce(t *testing.T) {
|
||||||
want := 120
|
want := 120
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
want,
|
want,
|
||||||
u.NewChain(nums).
|
chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Reduce(sum, 0))
|
Reduce(sum, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChainFilterMapContains(t *testing.T) {
|
func TestChainFilterMapContains(t *testing.T) {
|
||||||
assert.True(t, u.NewChain(nums).
|
assert.True(t, chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Contains(16))
|
Contains(16))
|
||||||
|
|
@ -46,7 +46,7 @@ func TestChainFilterMapContains(t *testing.T) {
|
||||||
func TestChainFilterMapEach(t *testing.T) {
|
func TestChainFilterMapEach(t *testing.T) {
|
||||||
want := []int{5, 17, 37, 65}
|
want := []int{5, 17, 37, 65}
|
||||||
res := make([]int, 0)
|
res := make([]int, 0)
|
||||||
u.NewChain(nums).
|
chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Each(func(n int) { res = append(res, n+1) })
|
Each(func(n int) { res = append(res, n+1) })
|
||||||
|
|
@ -54,14 +54,14 @@ func TestChainFilterMapEach(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChainFilterMapEvery(t *testing.T) {
|
func TestChainFilterMapEvery(t *testing.T) {
|
||||||
assert.True(t, u.NewChain(nums).
|
assert.True(t, chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Every(func(n int) bool { return n%4 == 0 }))
|
Every(func(n int) bool { return n%4 == 0 }))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChainFilterMapFind(t *testing.T) {
|
func TestChainFilterMapFind(t *testing.T) {
|
||||||
n, err := u.NewChain(nums).
|
n, err := chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Find(func(n int) bool { return n%4 == 0 })
|
Find(func(n int) bool { return n%4 == 0 })
|
||||||
|
|
@ -71,7 +71,7 @@ func TestChainFilterMapFind(t *testing.T) {
|
||||||
|
|
||||||
func TestChainFilterMapMax(t *testing.T) {
|
func TestChainFilterMapMax(t *testing.T) {
|
||||||
want := 64
|
want := 64
|
||||||
assert.Equal(t, want, u.NewChain(nums).
|
assert.Equal(t, want, chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Max())
|
Max())
|
||||||
|
|
@ -79,7 +79,7 @@ func TestChainFilterMapMax(t *testing.T) {
|
||||||
|
|
||||||
func TestChainFilterMapMin(t *testing.T) {
|
func TestChainFilterMapMin(t *testing.T) {
|
||||||
w := 4
|
w := 4
|
||||||
assert.Equal(t, w, u.NewChain(nums).
|
assert.Equal(t, w, chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Min())
|
Min())
|
||||||
|
|
@ -88,7 +88,7 @@ func TestChainFilterMapMin(t *testing.T) {
|
||||||
func TestChainFilterMapPartition(t *testing.T) {
|
func TestChainFilterMapPartition(t *testing.T) {
|
||||||
wantLeft := []int{4, 16}
|
wantLeft := []int{4, 16}
|
||||||
wantRight := []int{36, 64}
|
wantRight := []int{36, 64}
|
||||||
left, right := u.NewChain(nums).
|
left, right := chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Partition(func(n int) bool { return n < 20 })
|
Partition(func(n int) bool { return n < 20 })
|
||||||
|
|
@ -98,7 +98,7 @@ func TestChainFilterMapPartition(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChainFilterMapSome(t *testing.T) {
|
func TestChainFilterMapSome(t *testing.T) {
|
||||||
assert.True(t, u.NewChain(nums).
|
assert.True(t, chain.Of(nums).
|
||||||
Filter(isEven).
|
Filter(isEven).
|
||||||
Map(toSquare).
|
Map(toSquare).
|
||||||
Some(func(n int) bool { return n%64 == 0 }))
|
Some(func(n int) bool { return n%64 == 0 }))
|
||||||
Loading…
Reference in a new issue