mirror of
https://github.com/samber/lo.git
synced 2026-04-22 15:37:14 +08:00
feat: adding MeanByErr helper
This commit is contained in:
@@ -2119,6 +2119,18 @@ mean := lo.MeanBy([]float64{}, mapper)
|
||||
// 0
|
||||
```
|
||||
|
||||
```go
|
||||
// Use MeanByErr when the transform function can return an error
|
||||
list := []string{"aa", "bbb", "cccc", "ddddd"}
|
||||
mean, err := lo.MeanByErr(list, func(item string) (float64, error) {
|
||||
if item == "cccc" {
|
||||
return 0, fmt.Errorf("cccc is not allowed")
|
||||
}
|
||||
return float64(len(item)), nil
|
||||
})
|
||||
// 0, error("cccc is not allowed")
|
||||
```
|
||||
|
||||
[[play](https://go.dev/play/p/j7TsVwBOZ7P)]
|
||||
|
||||
### Mode
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: MeanBy
|
||||
slug: meanby
|
||||
sourceRef: math.go#L137
|
||||
sourceRef: math.go#L161
|
||||
category: core
|
||||
subCategory: math
|
||||
playUrl: https://go.dev/play/p/j7TsVwBOZ7P
|
||||
@@ -9,6 +9,7 @@ variantHelpers:
|
||||
- core#math#meanby
|
||||
similarHelpers:
|
||||
- core#math#mean
|
||||
- core#math#meanbyerr
|
||||
- core#math#mode
|
||||
- core#math#sum
|
||||
- core#math#sumby
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
name: MeanByErr
|
||||
slug: meanbyerr
|
||||
sourceRef: math.go#L172
|
||||
category: core
|
||||
subCategory: math
|
||||
variantHelpers:
|
||||
- core#math#meanbyerr
|
||||
similarHelpers:
|
||||
- core#math#meanby
|
||||
- core#math#mean
|
||||
- core#math#mode
|
||||
- core#math#sum
|
||||
- core#math#sumbyerr
|
||||
- core#math#product
|
||||
- core#math#productby
|
||||
- core#find#min
|
||||
- core#find#max
|
||||
- core#find#minby
|
||||
- core#find#maxby
|
||||
position: 91
|
||||
signatures:
|
||||
- "func MeanByErr[T any, R constraints.Float | constraints.Integer](collection []T, iteratee func(item T) (R, error)) (R, error)"
|
||||
---
|
||||
|
||||
Calculates the mean of values computed by a predicate. Returns 0 for an empty collection.
|
||||
|
||||
If the iteratee returns an error, iteration stops and the error is returned.
|
||||
|
||||
```go
|
||||
list := []string{"aa", "bbb", "cccc", "ddddd"}
|
||||
result, err := lo.MeanByErr(list, func(item string) (float64, error) {
|
||||
return float64(len(item)), nil
|
||||
})
|
||||
// 3.5, <nil>
|
||||
```
|
||||
|
||||
Example with error:
|
||||
|
||||
```go
|
||||
list := []string{"aa", "bbb", "cccc", "ddddd"}
|
||||
result, err := lo.MeanByErr(list, func(item string) (float64, error) {
|
||||
if item == "cccc" {
|
||||
return 0, fmt.Errorf("cccc is not allowed")
|
||||
}
|
||||
return float64(len(item)), nil
|
||||
})
|
||||
// 0, error("cccc is not allowed")
|
||||
```
|
||||
@@ -169,6 +169,21 @@ func MeanBy[T any, R constraints.Float | constraints.Integer](collection []T, it
|
||||
return sum / length
|
||||
}
|
||||
|
||||
// MeanByErr calculates the mean of a collection of numbers using the given return value from the iteration function.
|
||||
// If the iteratee returns an error, iteration stops and the error is returned.
|
||||
// If collection is empty 0 and nil error are returned.
|
||||
func MeanByErr[T any, R constraints.Float | constraints.Integer](collection []T, iteratee func(item T) (R, error)) (R, error) {
|
||||
length := R(len(collection))
|
||||
if length == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
sum, err := SumByErr(collection, iteratee)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return sum / length, nil
|
||||
}
|
||||
|
||||
// Mode returns the mode (most frequent value) of a collection.
|
||||
// If multiple values have the same highest frequency, then multiple values are returned.
|
||||
// If the collection is empty, then the zero value of T is returned.
|
||||
|
||||
+101
@@ -386,6 +386,107 @@ func TestMeanBy(t *testing.T) {
|
||||
is.Equal(uint32(0), result4)
|
||||
}
|
||||
|
||||
func TestMeanByErr(t *testing.T) {
|
||||
t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
testErr := assert.AnError
|
||||
|
||||
// Test normal operation (no error) - table driven
|
||||
tests := []struct {
|
||||
name string
|
||||
input interface{}
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
name: "float32 slice",
|
||||
input: []float32{2.3, 3.3, 4, 5.3},
|
||||
expected: float32(3.725),
|
||||
},
|
||||
{
|
||||
name: "int32 slice",
|
||||
input: []int32{2, 3, 4, 5},
|
||||
expected: int32(3),
|
||||
},
|
||||
{
|
||||
name: "uint32 slice",
|
||||
input: []uint32{2, 3, 4, 5},
|
||||
expected: uint32(3),
|
||||
},
|
||||
{
|
||||
name: "empty uint32 slice",
|
||||
input: []uint32{},
|
||||
expected: uint32(0),
|
||||
},
|
||||
{
|
||||
name: "nil int32 slice",
|
||||
input: ([]int32)(nil),
|
||||
expected: int32(0),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
switch input := tt.input.(type) {
|
||||
case []float32:
|
||||
result, err := MeanByErr(input, func(n float32) (float32, error) { return n, nil })
|
||||
is.NoError(err)
|
||||
is.InEpsilon(tt.expected.(float32), result, 1e-7)
|
||||
case []int32:
|
||||
result, err := MeanByErr(input, func(n int32) (int32, error) { return n, nil })
|
||||
is.NoError(err)
|
||||
is.Equal(tt.expected.(int32), result)
|
||||
case []uint32:
|
||||
result, err := MeanByErr(input, func(n uint32) (uint32, error) { return n, nil })
|
||||
is.NoError(err)
|
||||
is.Equal(tt.expected.(uint32), result)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Test error cases - table driven
|
||||
errorTests := []struct {
|
||||
name string
|
||||
input []int32
|
||||
errorAt int32
|
||||
expectedCalls int
|
||||
}{
|
||||
{
|
||||
name: "error at third element",
|
||||
input: []int32{1, 2, 3, 4, 5},
|
||||
errorAt: 3,
|
||||
expectedCalls: 3,
|
||||
},
|
||||
{
|
||||
name: "error at first element",
|
||||
input: []int32{1, 2, 3},
|
||||
errorAt: 1,
|
||||
expectedCalls: 1,
|
||||
},
|
||||
{
|
||||
name: "error at last element",
|
||||
input: []int32{1, 2, 3},
|
||||
errorAt: 3,
|
||||
expectedCalls: 3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range errorTests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
callbackCount := 0
|
||||
_, err := MeanByErr(tt.input, func(n int32) (int32, error) {
|
||||
callbackCount++
|
||||
if n == tt.errorAt {
|
||||
return 0, testErr
|
||||
}
|
||||
return n, nil
|
||||
})
|
||||
is.ErrorIs(err, testErr)
|
||||
is.Equal(tt.expectedCalls, callbackCount)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMode(t *testing.T) {
|
||||
t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
Reference in New Issue
Block a user