mirror of
https://github.com/samber/lo.git
synced 2026-04-22 15:37:14 +08:00
feat: adding FilterKeysErr + FilterValuesErr helpers
This commit is contained in:
@@ -2005,6 +2005,17 @@ result := FilterKeys(kv, func(k int, v string) bool {
|
||||
// [1]
|
||||
```
|
||||
|
||||
```go
|
||||
// Use FilterKeysErr when the predicate can return an error
|
||||
result, err := lo.FilterKeysErr(map[int]string{1: "foo", 2: "bar", 3: "baz"}, func(k int, v string) (bool, error) {
|
||||
if k == 3 {
|
||||
return false, fmt.Errorf("key 3 not allowed")
|
||||
}
|
||||
return v == "foo", nil
|
||||
})
|
||||
// []int(nil), error("key 3 not allowed")
|
||||
```
|
||||
|
||||
[[play](https://go.dev/play/p/OFlKXlPrBAe)]
|
||||
|
||||
### FilterValues
|
||||
@@ -2020,6 +2031,17 @@ result := FilterValues(kv, func(k int, v string) bool {
|
||||
// ["foo"]
|
||||
```
|
||||
|
||||
```go
|
||||
// Use FilterValuesErr when the predicate can return an error
|
||||
result, err := lo.FilterValuesErr(map[int]string{1: "foo", 2: "bar", 3: "baz"}, func(k int, v string) (bool, error) {
|
||||
if k == 3 {
|
||||
return false, fmt.Errorf("key 3 not allowed")
|
||||
}
|
||||
return v == "foo", nil
|
||||
})
|
||||
// []string(nil), error("key 3 not allowed")
|
||||
```
|
||||
|
||||
[[play](https://go.dev/play/p/YVD5r_h-LX-)]
|
||||
|
||||
### Range / RangeFrom / RangeWithSteps
|
||||
|
||||
@@ -9,6 +9,7 @@ variantHelpers:
|
||||
- core#map#filterkeys
|
||||
similarHelpers:
|
||||
- core#map#filtervalues
|
||||
- core#map#filterkeyserr
|
||||
- core#map#pickbykeys
|
||||
- core#map#omitbykeys
|
||||
- core#map#pickbyvalues
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: FilterKeysErr
|
||||
slug: filterkeyserr
|
||||
sourceRef: map.go#L498
|
||||
category: core
|
||||
subCategory: map
|
||||
signatures:
|
||||
- "func FilterKeysErr[K comparable, V any](in map[K]V, predicate func(key K, value V) (bool, error)) ([]K, error)"
|
||||
playUrl:
|
||||
variantHelpers:
|
||||
- core#map#filterkeyserr
|
||||
similarHelpers:
|
||||
- core#map#filterkeys
|
||||
- core#map#filtervalueserr
|
||||
- core#slice#filter
|
||||
position: 235
|
||||
---
|
||||
|
||||
Transforms a map into a slice of keys based on a predicate that can return an error. It is a mix of Filter() and Keys() with error handling. If the predicate returns true, the key is included. If the predicate returns an error, iteration stops immediately and returns the error.
|
||||
|
||||
```go
|
||||
kv := map[int]string{1:"foo", 2:"bar", 3:"baz"}
|
||||
result, err := lo.FilterKeysErr(kv, func(k int, v string) (bool, error) {
|
||||
if k == 3 {
|
||||
return false, errors.New("key 3 not allowed")
|
||||
}
|
||||
return v == "foo", nil
|
||||
})
|
||||
// []int(nil), error("key 3 not allowed")
|
||||
```
|
||||
|
||||
```go
|
||||
kv := map[int]string{1:"foo", 2:"bar", 3:"baz"}
|
||||
result, err := lo.FilterKeysErr(kv, func(k int, v string) (bool, error) {
|
||||
return v == "bar", nil
|
||||
})
|
||||
// []int{2}, nil
|
||||
```
|
||||
@@ -9,6 +9,7 @@ variantHelpers:
|
||||
- core#map#filtervalues
|
||||
similarHelpers:
|
||||
- core#map#filterkeys
|
||||
- core#map#filtervalueserr
|
||||
- core#map#pickbyvalues
|
||||
- core#map#omitbyvalues
|
||||
- core#map#pickbykeys
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: FilterValuesErr
|
||||
slug: filtervalueserr
|
||||
sourceRef: map.go#L519
|
||||
category: core
|
||||
subCategory: map
|
||||
signatures:
|
||||
- "func FilterValuesErr[K comparable, V any](in map[K]V, predicate func(key K, value V) (bool, error)) ([]V, error)"
|
||||
playUrl:
|
||||
variantHelpers:
|
||||
- core#map#filtervalueserr
|
||||
similarHelpers:
|
||||
- core#map#filtervalues
|
||||
- core#map#filterkeyserr
|
||||
- core#slice#filter
|
||||
position: 245
|
||||
---
|
||||
|
||||
Transforms a map into a slice of values based on a predicate that can return an error. It is a mix of Filter() and Values() with error handling. If the predicate returns true, the value is included. If the predicate returns an error, iteration stops immediately and returns the error.
|
||||
|
||||
```go
|
||||
kv := map[int]string{1:"foo", 2:"bar", 3:"baz"}
|
||||
result, err := lo.FilterValuesErr(kv, func(k int, v string) (bool, error) {
|
||||
if k == 3 {
|
||||
return false, errors.New("key 3 not allowed")
|
||||
}
|
||||
return v == "foo", nil
|
||||
})
|
||||
// []string(nil), error("key 3 not allowed")
|
||||
```
|
||||
|
||||
```go
|
||||
kv := map[int]string{1:"foo", 2:"bar", 3:"baz"}
|
||||
result, err := lo.FilterValuesErr(kv, func(k int, v string) (bool, error) {
|
||||
return v == "bar", nil
|
||||
})
|
||||
// []string{"bar"}, nil
|
||||
```
|
||||
@@ -2167,6 +2167,46 @@ func ExampleFilterValues() {
|
||||
// Output: [foo]
|
||||
}
|
||||
|
||||
func ExampleFilterKeysErr() {
|
||||
kv := map[int]string{1: "foo", 2: "bar", 3: "baz"}
|
||||
|
||||
result, err := FilterKeysErr(kv, func(k int, v string) (bool, error) {
|
||||
if k == 3 {
|
||||
return false, fmt.Errorf("key 3 not allowed")
|
||||
}
|
||||
return v == "foo", nil
|
||||
})
|
||||
fmt.Printf("%v, %v\n", result, err)
|
||||
|
||||
result, err = FilterKeysErr(kv, func(k int, v string) (bool, error) {
|
||||
return v == "bar", nil
|
||||
})
|
||||
fmt.Printf("%v, %v\n", result, err)
|
||||
// Output:
|
||||
// [], key 3 not allowed
|
||||
// [2], <nil>
|
||||
}
|
||||
|
||||
func ExampleFilterValuesErr() {
|
||||
kv := map[int]string{1: "foo", 2: "bar", 3: "baz"}
|
||||
|
||||
result, err := FilterValuesErr(kv, func(k int, v string) (bool, error) {
|
||||
if k == 3 {
|
||||
return false, fmt.Errorf("key 3 not allowed")
|
||||
}
|
||||
return v == "foo", nil
|
||||
})
|
||||
fmt.Printf("%v, %v\n", result, err)
|
||||
|
||||
result, err = FilterValuesErr(kv, func(k int, v string) (bool, error) {
|
||||
return v == "bar", nil
|
||||
})
|
||||
fmt.Printf("%v, %v\n", result, err)
|
||||
// Output:
|
||||
// [], key 3 not allowed
|
||||
// [bar], <nil>
|
||||
}
|
||||
|
||||
func ExampleRange() {
|
||||
result1 := Range(4)
|
||||
result2 := Range(-4)
|
||||
|
||||
@@ -489,3 +489,45 @@ func FilterValues[K comparable, V any](in map[K]V, predicate func(key K, value V
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FilterKeysErr transforms a map into a slice of keys based on predicate that can return an error.
|
||||
// It is a mix of lo.Filter() and lo.Keys() with error handling.
|
||||
// If the predicate returns true, the key is added to the result slice.
|
||||
// If the predicate returns an error, iteration stops immediately and returns the error.
|
||||
// The order of the keys in the input map is not specified.
|
||||
func FilterKeysErr[K comparable, V any](in map[K]V, predicate func(key K, value V) (bool, error)) ([]K, error) {
|
||||
result := make([]K, 0)
|
||||
|
||||
for k, v := range in {
|
||||
ok, err := predicate(k, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
result = append(result, k)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// FilterValuesErr transforms a map into a slice of values based on predicate that can return an error.
|
||||
// It is a mix of lo.Filter() and lo.Values() with error handling.
|
||||
// If the predicate returns true, the value is added to the result slice.
|
||||
// If the predicate returns an error, iteration stops immediately and returns the error.
|
||||
// The order of the keys in the input map is not specified.
|
||||
func FilterValuesErr[K comparable, V any](in map[K]V, predicate func(key K, value V) (bool, error)) ([]V, error) {
|
||||
result := make([]V, 0)
|
||||
|
||||
for k, v := range in {
|
||||
ok, err := predicate(k, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
+150
@@ -1234,6 +1234,156 @@ func TestFilterValues(t *testing.T) {
|
||||
is.Empty(result2)
|
||||
}
|
||||
|
||||
func TestFilterKeysErr(t *testing.T) {
|
||||
t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input map[int]string
|
||||
predicate func(int, string) (bool, error)
|
||||
want []int
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "filter by value",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return v == "foo", nil
|
||||
},
|
||||
want: []int{1},
|
||||
},
|
||||
{
|
||||
name: "empty map",
|
||||
input: map[int]string{},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
want: []int{},
|
||||
},
|
||||
{
|
||||
name: "filter all out",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return false, nil
|
||||
},
|
||||
want: []int{},
|
||||
},
|
||||
{
|
||||
name: "filter all in",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
want: []int{1, 2, 3},
|
||||
},
|
||||
{
|
||||
name: "error on specific key",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
if k == 2 {
|
||||
return false, fmt.Errorf("key 2 not allowed")
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
wantErr: "key 2 not allowed",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got, err := FilterKeysErr(tt.input, tt.predicate)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
is.Error(err)
|
||||
is.Equal(tt.wantErr, err.Error())
|
||||
is.Nil(got)
|
||||
} else {
|
||||
is.NoError(err)
|
||||
is.ElementsMatch(tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFilterValuesErr(t *testing.T) {
|
||||
t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input map[int]string
|
||||
predicate func(int, string) (bool, error)
|
||||
want []string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "filter by value",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return v == "foo", nil
|
||||
},
|
||||
want: []string{"foo"},
|
||||
},
|
||||
{
|
||||
name: "empty map",
|
||||
input: map[int]string{},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
name: "filter all out",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return false, nil
|
||||
},
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
name: "filter all in",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
return true, nil
|
||||
},
|
||||
want: []string{"foo", "bar", "baz"},
|
||||
},
|
||||
{
|
||||
name: "error on specific key",
|
||||
input: map[int]string{1: "foo", 2: "bar", 3: "baz"},
|
||||
predicate: func(k int, v string) (bool, error) {
|
||||
if k == 2 {
|
||||
return false, fmt.Errorf("key 2 not allowed")
|
||||
}
|
||||
return true, nil
|
||||
},
|
||||
wantErr: "key 2 not allowed",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
got, err := FilterValuesErr(tt.input, tt.predicate)
|
||||
|
||||
if tt.wantErr != "" {
|
||||
is.Error(err)
|
||||
is.Equal(tt.wantErr, err.Error())
|
||||
is.Nil(got)
|
||||
} else {
|
||||
is.NoError(err)
|
||||
is.ElementsMatch(tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAssign(b *testing.B) {
|
||||
counts := []int{32768, 1024, 128, 32, 2}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user