diff --git a/README.md b/README.md index 5f06dbb..ab1e8da 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ func main() { sum := func(n, acc int) int { return n + acc } res := u.Reduce(squares, sum, 0) - fmt.Println(res) // 110 + fmt.Println(res) // 120 } ``` @@ -82,17 +82,24 @@ go test ./... ### Collections -- `map` -- `filter` -- `reduce` -- `each` -- `some` -- `every` -- `find` -- `contains` (only numerics values at the moment) -- `max` -- `min` -- `partition` +- `Contains` (only numerics values at the moment) +- `Each` +- `Every` +- `Filter` +- `Find` +- `Map` +- `Max` +- `Min` +- `Partition` +- `Reduce` +- `Some` + +### Chaining + +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. ## Built With diff --git a/chain.go b/chain.go new file mode 100644 index 0000000..1a57244 --- /dev/null +++ b/chain.go @@ -0,0 +1,21 @@ +package underscore + +type Chain[T any] struct { + Value []T +} + +func NewChain[T any](value []T) Chain[T] { + return Chain[T]{Value: value} +} + +func (c Chain[T]) Filter(predicate func(n T) bool) Chain[T] { + return Chain[T]{Value: Filter(c.Value, predicate)} +} + +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) +} diff --git a/chain_test.go b/chain_test.go new file mode 100644 index 0000000..c1e2e9f --- /dev/null +++ b/chain_test.go @@ -0,0 +1,33 @@ +package underscore_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + 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 } + + want := []int{2, 4, 6, 8} + assert.Equal(t, want, u.NewChain(nums). + Filter(isEven). + Value) + + want = []int{4, 16, 36, 64} + assert.Equal(t, want, u.NewChain(nums). + Filter(isEven). + Map(toSquare). + Value) + + w := 120 + assert.Equal(t, w, u.NewChain(nums). + Filter(isEven). + Map(toSquare). + Reduce(sum, 0)) +} diff --git a/contains.go b/contains.go index 3d2102f..e4e49e6 100644 --- a/contains.go +++ b/contains.go @@ -1,5 +1,6 @@ package underscore +// Contains returns true if the value is present in the slice func Contains[T numbers](values []T, value T) bool { for _, v := range values { if v == value { diff --git a/docs/content/docs/chaining.md b/docs/content/docs/chaining.md new file mode 100644 index 0000000..7dfc750 --- /dev/null +++ b/docs/content/docs/chaining.md @@ -0,0 +1,32 @@ +--- +title: "Chaining" +date: 2021-12-31T13:11:41-04:00 +--- + +## NewChain + +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. + +```go +package main + +import ( + "fmt" + u "github.com/rjNemo/underscore" +) + +func main() { + sum := u.NewChain([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}). + // filter even numbers from the slice + Filter(func(n int) bool { return n%2 == 0 }). + // square every number in the slice + Map(func(n int) int { return n * n }). + // reduce to the sum + Reduce(func(n, acc int) int { return n + acc }, 0) + + fmt.Println(sum) // 120 +} +``` \ No newline at end of file diff --git a/docs/content/docs/collections.md b/docs/content/docs/collections.md index 6432a0b..70801b4 100644 --- a/docs/content/docs/collections.md +++ b/docs/content/docs/collections.md @@ -3,6 +3,25 @@ title: "Collections" date: 2021-12-30T13:24:39-04:00 --- +## Contains + +`Contains` returns true if the value is present in the slice. + +```go +package main + +import ( + "fmt" + u "github.com/rjNemo/underscore" +) + +func main() { + nums := []int{1, 3, 5, 7, 9} + + fmt.Println(u.Contains(nums, 5)) // true +} +``` + ## Each `Each` iterates over a slice of elements, yielding each in turn to an action function. diff --git a/examples/chaining.go b/examples/chaining.go new file mode 100644 index 0000000..a62d1d1 --- /dev/null +++ b/examples/chaining.go @@ -0,0 +1,19 @@ +package examples + +import ( + "fmt" + + u "github.com/rjNemo/underscore" +) + +func main() { + sum := u.NewChain([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}). + // filter even numbers from the slice + Filter(func(n int) bool { return n%2 == 0 }). + // square every number in the slice + Map(func(n int) int { return n * n }). + // reduce to the sum + Reduce(func(n, acc int) int { return n + acc }, 0) + + fmt.Println(sum) +} diff --git a/examples/filterMapReduce.go b/examples/filterMapReduce.go index 8912957..76d33b0 100644 --- a/examples/filterMapReduce.go +++ b/examples/filterMapReduce.go @@ -11,7 +11,7 @@ func main() { // filter even numbers from the slice isEven := func(n int) bool { return n%2 == 0 } evens := u.Filter(numbers, isEven) - // square every numbers numbers in the slice + // square every number in the slice toSquare := func(n int) int { return n * n } squares := u.Map(evens, toSquare) // reduce to the sum