Skip to content

Commit

Permalink
#21 Add TakeLastWhile implements
Browse files Browse the repository at this point in the history
  • Loading branch information
meian committed Feb 4, 2022
1 parent d7eaa9d commit 70a111e
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 0 deletions.
64 changes: 64 additions & 0 deletions take_last.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
101 changes: 101 additions & 0 deletions take_last_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]
}

0 comments on commit 70a111e

Please sign in to comment.