From 8016defee80eb134dbdca95faf505c9904746529 Mon Sep 17 00:00:00 2001 From: "John.Devitt@cdp.net" Date: Tue, 3 Dec 2024 21:30:51 +0000 Subject: [PATCH] feat: add Product and ProductBy functions --- README.md | 39 +++++++++++++++++++++++++++++++++++---- math.go | 38 ++++++++++++++++++++++++++++++++++++++ math_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 73c33223..0bc00ef4 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,8 @@ Supported math helpers: - [Clamp](#clamp) - [Sum](#sum) - [SumBy](#sumby) +- [Product](#product) +- [ProductBy](#productby) - [Mean](#mean) - [MeanBy](#meanby) @@ -787,7 +789,6 @@ l := lo.DropByIndex([]int{0, 1, 2, 3, 4, 5}, 2, 4, -1) [[play](https://go.dev/play/p/JswS7vXRJP2)] - ### Reject The opposite of Filter, this method returns the elements of collection that predicate does not return truthy for. @@ -806,6 +807,7 @@ odd := lo.Reject([]int{1, 2, 3, 4}, func(x int, _ int) bool { The opposite of FilterMap, this method returns a slice which obtained after both filtering and mapping using the given callback function. The callback function should return two values: + - the result of the mapping operation and - whether the result element should be included or not. @@ -1062,7 +1064,7 @@ keys := lo.Keys(map[string]int{"foo": 1, "bar": 2}, map[string]int{"bar": 3}) ### UniqKeys -Creates an array of unique map keys. +Creates an array of unique map keys. ```go keys := lo.UniqKeys(map[string]int{"foo": 1, "bar": 2}, map[string]int{"baz": 3}) @@ -1411,7 +1413,35 @@ sum := lo.SumBy(strings, func(item string) int { // 6 ``` -[[play](https://go.dev/play/p/Dz_a_7jN_ca)] +### Product + +Calculates the product of the values in a collection. + +If collection is empty 0 is returned. + +```go +list := []int{1, 2, 3, 4, 5} +product := lo.Product(list) +// 120 +``` + +[[play](https://go.dev/play/p/2_kjM_smtAH)] + +### ProductBy + +Calculates the product of the values in a collection using the given return value from the iteration function. + +If collection is empty 0 is returned. + +```go +strings := []string{"foo", "bar"} +product := lo.ProductBy(strings, func(item string) int { + return len(item) +}) +// 9 +``` + +[[play](https://go.dev/play/p/wadzrWr9Aer)] ### Mean @@ -2421,6 +2451,7 @@ first := lo.FirstOrEmpty([]int{1, 2, 3}) first := lo.FirstOrEmpty([]int{}) // 0 ``` + ### FirstOr Returns the first element of a collection or the fallback value if empty. @@ -2458,6 +2489,7 @@ last := lo.LastOrEmpty([]int{1, 2, 3}) last := lo.LastOrEmpty([]int{}) // 0 ``` + ### LastOr Returns the first element of a collection or the fallback value if empty. @@ -3213,7 +3245,6 @@ iterations, duration, ok := lo.WaitFor(laterTrue, 10*time.Millisecond, 5*time.Mi // false ``` - ### WaitForWithContext Runs periodically until a condition is validated or context is invalid. diff --git a/math.go b/math.go index 7a18ca62..1cfb11ec 100644 --- a/math.go +++ b/math.go @@ -85,6 +85,44 @@ func SumBy[T any, R constraints.Float | constraints.Integer | constraints.Comple return sum } +// Product gets the product of the values in a collection. If collection is empty 0 is returned. +// Play: https://go.dev/play/p/2_kjM_smtAH +func Product[T constraints.Float | constraints.Integer | constraints.Complex](collection []T) T { + + if collection == nil { + return 0 + } + + if len(collection) == 0 { + return 0 + } + + var product T = 1 + for i := range collection { + product *= collection[i] + } + return product +} + +// ProductBy summarizes the values in a collection using the given return value from the iteration function. If collection is empty 0 is returned. +// Play: https://go.dev/play/p/wadzrWr9Aer +func ProductBy[T any, R constraints.Float | constraints.Integer | constraints.Complex](collection []T, iteratee func(item T) R) R { + + if collection == nil { + return 0 + } + + if len(collection) == 0 { + return 0 + } + + var product R = 1 + for i := range collection { + product = product * iteratee(collection[i]) + } + return product +} + // Mean calculates the mean of a collection of numbers. func Mean[T constraints.Float | constraints.Integer](collection []T) T { var length = T(len(collection)) diff --git a/math_test.go b/math_test.go index 8e5efeda..3c8e9016 100644 --- a/math_test.go +++ b/math_test.go @@ -98,6 +98,46 @@ func TestSumBy(t *testing.T) { is.Equal(result5, complex128(6_6)) } +func TestProduct(t *testing.T) { + is := assert.New(t) + + result1 := Product([]float32{2.3, 3.3, 4, 5.3}) + result2 := Product([]int32{2, 3, 4, 5}) + result3 := Product([]int32{7, 8, 9, 0}) + result4 := Product([]int32{7, -1, 9, 2}) + result5 := Product([]uint32{2, 3, 4, 5}) + result6 := Product([]uint32{}) + result7 := Product([]complex128{4_4, 2_2}) + + is.Equal(result1, float32(160.908)) + is.Equal(result2, int32(120)) + is.Equal(result3, int32(0)) + is.Equal(result4, int32(-126)) + is.Equal(result5, uint32(120)) + is.Equal(result6, uint32(0)) + is.Equal(result7, complex128(96_8)) +} + +func TestProductBy(t *testing.T) { + is := assert.New(t) + + result1 := ProductBy([]float32{2.3, 3.3, 4, 5.3}, func(n float32) float32 { return n }) + result2 := ProductBy([]int32{2, 3, 4, 5}, func(n int32) int32 { return n }) + result3 := ProductBy([]int32{7, 8, 9, 0}, func(n int32) int32 { return n }) + result4 := ProductBy([]int32{7, -1, 9, 2}, func(n int32) int32 { return n }) + result5 := ProductBy([]uint32{2, 3, 4, 5}, func(n uint32) uint32 { return n }) + result6 := ProductBy([]uint32{}, func(n uint32) uint32 { return n }) + result7 := ProductBy([]complex128{4_4, 2_2}, func(n complex128) complex128 { return n }) + + is.Equal(result1, float32(160.908)) + is.Equal(result2, int32(120)) + is.Equal(result3, int32(0)) + is.Equal(result4, int32(-126)) + is.Equal(result5, uint32(120)) + is.Equal(result6, uint32(0)) + is.Equal(result7, complex128(96_8)) +} + func TestMean(t *testing.T) { t.Parallel() is := assert.New(t)