Skip to content

Commit

Permalink
Merge pull request #82 from meian/21-last-implements
Browse files Browse the repository at this point in the history
#21 last implements
  • Loading branch information
meian authored Feb 3, 2022
2 parents 3c6f8a5 + d68fab8 commit 548926d
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 0 deletions.
60 changes: 60 additions & 0 deletions last.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package gcf

type lastIterable[T any] struct {
itb Iterable[T]
count int
}

type lastIterator[T any] struct {
it Iterator[T]
count int
i int
built bool
current T
}

// Last makes Iterable with count elements from end.
//
// itb := gcf.FromSlice([]{1, 2, 3})
// itb = gcf.Last(itb, 2)
//
// If count is 0 or negative, returns empty Iterable.
func Last[T any](itb Iterable[T], count int) Iterable[T] {
if isEmpty(itb) {
return orEmpty(itb)
}
if count < 1 {
return empty[T]()
}
return &lastIterable[T]{itb, count}
}

func (itb *lastIterable[T]) Iterator() Iterator[T] {
return &lastIterator[T]{itb.itb.Iterator(), itb.count, 0, false, zero[T]()}
}

func (it *lastIterator[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 *lastIterator[T]) Current() T {
return it.current
}

func (it *lastIterator[T]) build() {
s := iteratorToSlice(it.it)
if len(s) <= it.count {
it.it = makeSliceIterator(s)
} else {
it.it = makeSliceIterator(s[len(s)-it.count:])
}
it.built = true
}
101 changes: 101 additions & 0 deletions last_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package gcf_test

import (
"fmt"
"testing"

"github.com/meian/gcf"
"github.com/stretchr/testify/assert"
)

func TestLast(t *testing.T) {
type args struct {
itb gcf.Iterable[int]
count int
}
tests := []struct {
name string
args args
want []int
}{
{
name: "last 1 from slice 3",
args: args{
itb: gcf.FromSlice([]int{1, 2, 3}),
count: 1,
},
want: []int{3},
},
{
name: "last 2 from slice 3",
args: args{
itb: gcf.FromSlice([]int{1, 2, 3}),
count: 2,
},
want: []int{2, 3},
},
{
name: "last 3 from slice 3",
args: args{
itb: gcf.FromSlice([]int{1, 2, 3}),
count: 3,
},
want: []int{1, 2, 3},
},
{
name: "last 4 from slice 3",
args: args{
itb: gcf.FromSlice([]int{1, 2, 3}),
count: 4,
},
want: []int{1, 2, 3},
},
{
name: "last 0 from slice 3",
args: args{
itb: gcf.FromSlice([]int{1, 2, 3}),
count: 0,
},
want: []int{},
},
{
name: "last negative",
args: args{
itb: gcf.FromSlice([]int{1, 2, 3}),
count: -1,
},
want: []int{},
},
{
name: "nil Iterable",
args: args{
itb: nil,
count: 3,
},
want: []int{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
itb := gcf.Last(tt.args.itb, tt.args.count)
s := gcf.ToSlice(itb)
assert.Equal(t, tt.want, s)
})
}

itb := gcf.FromSlice([]int{1, 2, 3})
itb = gcf.Last(itb, 2)
testBeforeAndAfter(t, itb)

testEmptyChain(t, func(itb gcf.Iterable[int]) gcf.Iterable[int] {
return gcf.Last(itb, 2)
})
}

func ExampleLast() {
itb := gcf.FromSlice([]int{1, 2, 3, 4, 5})
itb = gcf.Last(itb, 3)
fmt.Println(gcf.ToSlice(itb))
// Output:
// [3 4 5]
}

0 comments on commit 548926d

Please sign in to comment.