From 80bb7cefc6bb9fe37dffeae112490e1b1946d354 Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Thu, 27 Jun 2024 16:17:40 +0200 Subject: [PATCH] feat: adding RejectMap (#473) --- README.md | 18 +++++++++++++++++- slice.go | 16 ++++++++++++++++ slice_test.go | 23 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 55bfd2f4..b66a9f65 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ Supported helpers for slices: - [DropWhile](#dropwhile) - [DropRightWhile](#droprightwhile) - [Reject](#reject) +- [RejectMap](#rejectmap) - [FilterReject](#filterreject) - [Count](#count) - [CountBy](#countby) @@ -750,9 +751,24 @@ odd := lo.Reject([]int{1, 2, 3, 4}, func(x int, _ int) bool { [[play](https://go.dev/play/p/YkLMODy1WEL)] +### RejectMap + +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. + +```go +items := lo.RejectMap([]int{1, 2, 3, 4}, func(x int, _ int) (int, bool) { + return x*10, x%2 == 0 +}) +// []int{10, 30} +``` + ### 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. +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 { diff --git a/slice.go b/slice.go index 1da55ee1..ce5189e0 100644 --- a/slice.go +++ b/slice.go @@ -431,6 +431,22 @@ func Reject[V any](collection []V, predicate func(item V, index int) bool) []V { return result } +// RejectMap is 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. +func RejectMap[T any, R any](collection []T, callback func(item T, index int) (R, bool)) []R { + result := []R{} + + for i, item := range collection { + if r, ok := callback(item, i); !ok { + result = append(result, r) + } + } + + 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) { diff --git a/slice_test.go b/slice_test.go index a404501f..e7e717fd 100644 --- a/slice_test.go +++ b/slice_test.go @@ -500,6 +500,29 @@ func TestReject(t *testing.T) { is.Equal(r2, []string{"foo", "bar"}) } +func TestRejectMap(t *testing.T) { + t.Parallel() + is := assert.New(t) + + r1 := RejectMap([]int64{1, 2, 3, 4}, func(x int64, _ int) (string, bool) { + if x%2 == 0 { + return strconv.FormatInt(x, 10), false + } + return "", true + }) + r2 := RejectMap([]string{"cpu", "gpu", "mouse", "keyboard"}, func(x string, _ int) (string, bool) { + if strings.HasSuffix(x, "pu") { + return "xpu", false + } + return "", true + }) + + is.Equal(len(r1), 2) + is.Equal(len(r2), 2) + is.Equal(r1, []string{"2", "4"}) + is.Equal(r2, []string{"xpu", "xpu"}) +} + func TestFilterReject(t *testing.T) { t.Parallel() is := assert.New(t)