From 4c3ac97ef4342391eb05d8200df320ee379a8b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Fernandes?= <9938253+joaofnds@users.noreply.github.com> Date: Wed, 11 Jan 2023 09:55:09 -0300 Subject: [PATCH] feat(generic): add `TakeUntil` (#85) https://laravel.com/docs/9.x/collections#method-takeuntil --- TODO.md | 2 +- generic.go | 5 +++ generic_test.go | 50 +++++++++++++++++++++- tests/benchmark/generic/take_until_test.go | 17 ++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 tests/benchmark/generic/take_until_test.go diff --git a/TODO.md b/TODO.md index 845f8d0..d47d201 100644 --- a/TODO.md +++ b/TODO.md @@ -97,7 +97,7 @@ Not all methods will make sense on Go and won't be implemented. - [ ] splitIn - [x] sum (Sum, SumBy) - [x] take -- [ ] takeUntil +- [x] takeUntil - [x] takeWhile - [x] tap - [ ] times diff --git a/generic.go b/generic.go index eabcdbf..05e62b7 100644 --- a/generic.go +++ b/generic.go @@ -788,3 +788,8 @@ func TakeWhile[V any](slice []V, matcher AnyMatcher) []V { return slice } + +// TakeUntil returns items in the `slice` until `matcher` returns true +func TakeUntil[V any](slice []V, matcher AnyMatcher) []V { + return TakeWhile(slice, Not(matcher)) +} diff --git a/generic_test.go b/generic_test.go index 9b6243d..11cbcb6 100644 --- a/generic_test.go +++ b/generic_test.go @@ -2979,7 +2979,7 @@ func TestTakeWhile(t *testing.T) { expected: []int{1, 2}, }, { - name: "1 through 5 take while 10", + name: "1 through 5 take while less than 10", slice: []int{1, 2, 3, 4, 5}, matcher: ValueLT(10), expected: []int{1, 2, 3, 4, 5}, @@ -3012,3 +3012,51 @@ func TestTakeWhile(t *testing.T) { }) } } + +func TestTakeUntil(t *testing.T) { + testCases := []struct { + name string + slice []int + matcher AnyMatcher + expected []int + }{ + { + name: "1 through 5 take until greater than 3", + slice: []int{1, 2, 3, 4, 5}, + matcher: ValueGT(3), + expected: []int{1, 2, 3}, + }, + { + name: "1 through 5 take until less than 10", + slice: []int{1, 2, 3, 4, 5}, + matcher: ValueLT(10), + expected: []int{}, + }, + { + name: "1 through 5 take until less than 0", + slice: []int{1, 2, 3, 4, 5}, + matcher: ValueLT(0), + expected: []int{1, 2, 3, 4, 5}, + }, + { + name: "empty slice with matcher returning true", + slice: []int{}, + matcher: func(_, _ any) bool { return true }, + expected: []int{}, + }, + { + name: "empty slice with matcher returning false", + slice: []int{}, + matcher: func(_, _ any) bool { return false }, + expected: []int{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if got := TakeUntil(tc.slice, tc.matcher); !reflect.DeepEqual(got, tc.expected) { + t.Errorf("Expected '%v'. Got '%v'", tc.expected, got) + } + }) + } +} diff --git a/tests/benchmark/generic/take_until_test.go b/tests/benchmark/generic/take_until_test.go new file mode 100644 index 0000000..6b105f3 --- /dev/null +++ b/tests/benchmark/generic/take_until_test.go @@ -0,0 +1,17 @@ +package generic + +import ( + "testing" + + . "github.com/thefuga/go-collections" + "github.com/thefuga/go-collections/tests/benchmark" +) + +func BenchmarkTakeUntil(b *testing.B) { + slice := benchmark.BuildIntSlice() + matcher := ValueGT(len(slice) / 2) + + for n := 0; n < b.N; n++ { + TakeUntil(slice, matcher) + } +}