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) + } +}