Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Product and ProductBy functions #566

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ Supported math helpers:
- [Clamp](#clamp)
- [Sum](#sum)
- [SumBy](#sumby)
- [Product](#product)
- [ProductBy](#productby)
- [Mean](#mean)
- [MeanBy](#meanby)

Expand Down Expand Up @@ -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.
Expand All @@ -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.

Expand Down Expand Up @@ -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})
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
38 changes: 38 additions & 0 deletions math.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
40 changes: 40 additions & 0 deletions math_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down