From 70a111ee9f14bb690d44356fc78113c9e81d294d Mon Sep 17 00:00:00 2001 From: kitamin <11195207+meian@users.noreply.github.com> Date: Fri, 4 Feb 2022 23:00:15 +0900 Subject: [PATCH] #21 Add TakeLastWhile implements --- take_last.go | 64 +++++++++++++++++++++++++++++ take_last_test.go | 101 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) diff --git a/take_last.go b/take_last.go index 5887104..89b7f55 100644 --- a/take_last.go +++ b/take_last.go @@ -58,3 +58,67 @@ func (it *takeLastIterator[T]) build() { } it.built = true } + +type takeLastWhileIterable[T any] struct { + itb Iterable[T] + whileFunc func(v T) bool +} + +type takeLastWhileIterator[T any] struct { + it Iterator[T] + whileFunc func(v T) bool + built bool + current T +} + +// TakeLastWhile makes Iterable with elements in which whileFunc is true from end. +// +// itb := gcf.FromSlice([]{1, 2, 3}) +// itb = gcf.TakeLastWhile(itb, func(v int) bool { return v >= 2 }) +// +// If whileFunc is nil, returns empty Iterable. +func TakeLastWhile[T any](itb Iterable[T], whileFunc func(v T) bool) Iterable[T] { + if isEmpty(itb) { + return orEmpty(itb) + } + if whileFunc == nil { + return empty[T]() + } + return &takeLastWhileIterable[T]{itb, whileFunc} +} + +func (itb *takeLastWhileIterable[T]) Iterator() Iterator[T] { + return &takeLastWhileIterator[T]{itb.itb.Iterator(), itb.whileFunc, false, zero[T]()} +} + +func (it *takeLastWhileIterator[T]) MoveNext() bool { + if !it.built { + it.build() + } + if !it.it.MoveNext() { + it.current = zero[T]() + return false + } + it.current = it.it.Current() + return true +} + +func (it *takeLastWhileIterator[T]) Current() T { + return it.current +} + +func (it *takeLastWhileIterator[T]) build() { + s := iteratorToSlice(it.it) + if !it.whileFunc(s[len(s)-1]) { + it.it = emptyIter[T]() + } else { + for i := len(s) - 2; i >= 0; i-- { + if !it.whileFunc(s[i]) { + s = s[i+1:] + break + } + } + it.it = makeSliceIterator(s) + } + it.built = true +} diff --git a/take_last_test.go b/take_last_test.go index 572bdd5..23c515a 100644 --- a/take_last_test.go +++ b/take_last_test.go @@ -99,3 +99,104 @@ func ExampleTakeLast() { // Output: // [3 4 5] } + +func TestTakeLastWhile(t *testing.T) { + type args struct { + itb gcf.Iterable[int] + whileFunc func(v int) bool + } + tests := []struct { + name string + args args + want []int + }{ + { + name: "all true", + args: args{ + itb: gcf.FromSlice([]int{1, 2, 3}), + whileFunc: func(v int) bool { return true }, + }, + want: []int{1, 2, 3}, + }, + { + name: "all false", + args: args{ + itb: gcf.FromSlice([]int{1, 2, 3}), + whileFunc: func(v int) bool { return false }, + }, + want: []int{}, + }, + { + name: "partial true from end", + args: args{ + itb: gcf.FromSlice([]int{1, 2, 3}), + whileFunc: func(v int) bool { return v >= 2 }, + }, + want: []int{2, 3}, + }, + { + name: "partial true not from end", + args: args{ + itb: gcf.FromSlice([]int{1, 2, 3}), + whileFunc: func(v int) bool { return v <= 2 }, + }, + want: []int{}, + }, + { + name: "1 element with filter true", + args: args{ + itb: gcf.FromSlice([]int{1}), + whileFunc: func(v int) bool { return true }, + }, + want: []int{1}, + }, + { + name: "1 element with filter false", + args: args{ + itb: gcf.FromSlice([]int{1}), + whileFunc: func(v int) bool { return false }, + }, + want: []int{}, + }, + { + name: "nil func", + args: args{ + itb: gcf.FromSlice([]int{1, 2, 3}), + whileFunc: nil, + }, + want: []int{}, + }, + { + name: "nil Iterable", + args: args{ + itb: nil, + whileFunc: func(v int) bool { return true }, + }, + want: []int{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + itb := gcf.TakeLastWhile(tt.args.itb, tt.args.whileFunc) + s := gcf.ToSlice(itb) + assert.Equal(t, tt.want, s) + }) + } + + itb := gcf.FromSlice([]int{1, 2, 3}) + itb = gcf.TakeLastWhile(itb, func(v int) bool { return v > 2 }) + testBeforeAndAfter(t, itb) + + testEmptyChain(t, func(itb gcf.Iterable[int]) gcf.Iterable[int] { + return gcf.TakeLastWhile(itb, func(v int) bool { return true }) + }) +} + +func ExampleTakeLastWhile() { + itb := gcf.FromSlice([]int{1, 3, 5, 7, 2, 4, 6, 8, 9}) + itb = gcf.TakeLastWhile(itb, func(v int) bool { return v > 3 }) + s := gcf.ToSlice(itb) + fmt.Println(s) + // Output: + // [4 6 8 9] +}