diff --git a/README.md b/README.md index ec050cf5..55bfd2f4 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ Supported helpers for slices: - [DropWhile](#dropwhile) - [DropRightWhile](#droprightwhile) - [Reject](#reject) +- [FilterReject](#filterreject) - [Count](#count) - [CountBy](#countby) - [CountValues](#countvalues) @@ -749,6 +750,18 @@ odd := lo.Reject([]int{1, 2, 3, 4}, func(x int, _ int) bool { [[play](https://go.dev/play/p/YkLMODy1WEL)] +### FilterReject + +FilterReject mixes Filter and Reject, this method returns two slices, one for the elements of collection that predicate returns truthy for and one for the elements that predicate does not return truthy for. + +```go +kept, rejected := lo.FilterReject([]int{1, 2, 3, 4}, func(x int, _ int) bool { + return x%2 == 0 +}) +// []int{2, 4} +// []int{1, 3} +``` + ### Count Counts the number of elements in the collection that compare equal to value. diff --git a/slice.go b/slice.go index 4bfed2de..1da55ee1 100644 --- a/slice.go +++ b/slice.go @@ -431,6 +431,23 @@ func Reject[V any](collection []V, predicate func(item V, index int) bool) []V { return result } +// FilterReject mixes Filter and Reject, this method returns two slices, one for the elements of collection that +// predicate returns truthy for and one for the elements that predicate does not return truthy for. +func FilterReject[V any](collection []V, predicate func(V, int) bool) (kept []V, rejected []V) { + kept = make([]V, 0, len(collection)) + rejected = make([]V, 0, len(collection)) + + for i, item := range collection { + if predicate(item, i) { + kept = append(kept, item) + } else { + rejected = append(rejected, item) + } + } + + return kept, rejected +} + // Count counts the number of elements in the collection that compare equal to value. // Play: https://go.dev/play/p/Y3FlK54yveC func Count[T comparable](collection []T, value T) (count int) { diff --git a/slice_test.go b/slice_test.go index 03326a01..a404501f 100644 --- a/slice_test.go +++ b/slice_test.go @@ -388,7 +388,7 @@ func TestAssociate(t *testing.T) { func TestSliceToMap(t *testing.T) { t.Parallel() - + type foo struct { baz string bar int @@ -500,6 +500,25 @@ func TestReject(t *testing.T) { is.Equal(r2, []string{"foo", "bar"}) } +func TestFilterReject(t *testing.T) { + t.Parallel() + is := assert.New(t) + + left1, right1 := FilterReject([]int{1, 2, 3, 4}, func(x int, _ int) bool { + return x%2 == 0 + }) + + is.Equal(left1, []int{2, 4}) + is.Equal(right1, []int{1, 3}) + + left2, right2 := FilterReject([]string{"Smith", "foo", "Domin", "bar", "Olivia"}, func(x string, _ int) bool { + return len(x) > 3 + }) + + is.Equal(left2, []string{"Smith", "Domin", "Olivia"}) + is.Equal(right2, []string{"foo", "bar"}) +} + func TestCount(t *testing.T) { t.Parallel() is := assert.New(t) @@ -626,7 +645,7 @@ func TestSlice(t *testing.T) { out16 := Slice(in, -10, 1) out17 := Slice(in, -1, 3) out18 := Slice(in, -10, 7) - + is.Equal([]int{}, out1) is.Equal([]int{0}, out2) is.Equal([]int{0, 1, 2, 3, 4}, out3)