diff --git a/README.md b/README.md index 99ed8ce..97dd671 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ gollection is golang collection util library (inspired by [kotlin collection](ht - fold - map - reduce +- skip ([java8](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#skip-long-)) - sortBy - take diff --git a/example_test.go b/example_test.go index 86d3678..be6aaaa 100644 --- a/example_test.go +++ b/example_test.go @@ -80,6 +80,17 @@ func Example_reduce() { // Output: 55 } +func Example_skip() { + arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + + res, err := gollection.New(arr).Skip(3).Result() + fmt.Println(res, err) + res, err = gollection.New(arr).Skip(30).Result() + fmt.Println(res, err) + // Output: [4 5 6 7 8 9 10] + // [] +} + func Example_sort() { arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1} diff --git a/examples/skip/main.go b/examples/skip/main.go new file mode 100644 index 0000000..36f2353 --- /dev/null +++ b/examples/skip/main.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + + "github.com/azihsoyn/gollection" +) + +func main() { + arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + + res, _ := gollection.New(arr).Skip(3).Result() + fmt.Println("origin : ", arr) + fmt.Println("ret : ", res) // {4, 5, 6, 7, 8, 9, 10} + + res, _ = gollection.New(arr).Skip(30).Result() + fmt.Println("origin : ", arr) + fmt.Println("ret : ", res) // {} +} diff --git a/skip.go b/skip.go new file mode 100644 index 0000000..0919411 --- /dev/null +++ b/skip.go @@ -0,0 +1,80 @@ +package gollection + +import ( + "fmt" + "reflect" +) + +func (g *gollection) Skip(n int) *gollection { + if g.err != nil { + return &gollection{err: g.err} + } + + if g.ch != nil { + return g.skipStream(n) + } + + return g.skip(n) +} + +func (g *gollection) skip(n int) *gollection { + sv, err := g.validateSlice("Take") + if err != nil { + return &gollection{err: err} + } + + if n < 0 { + return &gollection{err: fmt.Errorf("gollection.Skip called with invalid argument. should be larger than 0")} + } + + limit := sv.Len() + start := n + if limit < start { + start = limit + } + + ret := reflect.MakeSlice(sv.Type(), 0, limit-start) + + for i := start; i < limit; i++ { + ret = reflect.Append(ret, sv.Index(i)) + } + + return &gollection{ + slice: ret.Interface(), + } +} + +func (g *gollection) skipStream(n int) *gollection { + next := &gollection{ + ch: make(chan interface{}), + } + + var initialized bool + go func() { + i := 0 + for { + select { + case v, ok := <-g.ch: + // initialize next stream type + if ok && !initialized { + next.ch <- v + initialized = true + continue + } + + if ok { + i++ + if n < i { + next.ch <- v + } + } else { + close(next.ch) + return + } + default: + continue + } + } + }() + return next +} diff --git a/skip_test.go b/skip_test.go new file mode 100644 index 0000000..272fa22 --- /dev/null +++ b/skip_test.go @@ -0,0 +1,74 @@ +package gollection_test + +import ( + "testing" + "time" + + "github.com/azihsoyn/gollection" + "github.com/stretchr/testify/assert" +) + +func TestSkip(t *testing.T) { + assert := assert.New(t) + arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + expect := []int{4, 5, 6, 7, 8, 9, 10} + + res, err := gollection.New(arr).Skip(3).Result() + assert.NoError(err) + assert.Equal(expect, res) + + expect = []int{} + res, err = gollection.New(arr).Skip(30).Result() + assert.NoError(err) + assert.Equal(expect, res) +} + +func TestSkip_NotSlice(t *testing.T) { + assert := assert.New(t) + _, err := gollection.New("not slice value").Skip(0).Result() + assert.Error(err) +} + +func TestSkip_InvalidArgument(t *testing.T) { + assert := assert.New(t) + _, err := gollection.New([]int{1, 2, 3}).Skip(-1).Result() + assert.Error(err) +} + +func TestSkip_HavingError(t *testing.T) { + assert := assert.New(t) + _, err := gollection.New("not slice value").Skip(0).Skip(0).Result() + assert.Error(err) +} + +func TestSkip_Stream(t *testing.T) { + assert := assert.New(t) + arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + expect := []int{4, 5, 6, 7, 8, 9, 10} + + res, err := gollection.NewStream(arr).Skip(3).Result() + assert.NoError(err) + assert.Equal(expect, res) + + expect = []int{} + res, err = gollection.NewStream(arr).Skip(30).Result() + assert.NoError(err) + assert.Equal(expect, res) + + gollection.NewStream(arr).Filter(func(v int) bool { + time.Sleep(1) + return true + }).Skip(100) +} + +func TestSkip_Stream_NotSlice(t *testing.T) { + assert := assert.New(t) + _, err := gollection.NewStream("not slice value").Skip(0).Result() + assert.Error(err) +} + +func TestSkip_Stream_HavingError(t *testing.T) { + assert := assert.New(t) + _, err := gollection.NewStream("not slice value").Skip(0).Skip(0).Result() + assert.Error(err) +}