Skip to content

Commit 4d25512

Browse files
authored
Merge pull request #27 from williammartin/add-chain-iterator
Add Chain Iterator
2 parents e102646 + a133c03 commit 4d25512

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

iter/chain.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package iter
2+
3+
import "github.com/BooleanCat/go-functional/option"
4+
5+
// ChainIter implements `Chain`. See `Chain`'s documentation.
6+
type ChainIter[T any] struct {
7+
iterators []Iterator[T]
8+
iteratorIndex int
9+
}
10+
11+
// Chain instantiates a `ChainIter` that will yield all items in the provided iterators to exhaustion, from left to right.
12+
func Chain[T any](iterators ...Iterator[T]) *ChainIter[T] {
13+
return &ChainIter[T]{iterators, 0}
14+
}
15+
16+
// Next implements the Iterator interface for `Chain`.
17+
func (iter *ChainIter[T]) Next() option.Option[T] {
18+
for {
19+
// If the index is equal to the number of iterators then we have exhausted them all.
20+
if iter.iteratorIndex == len(iter.iterators) {
21+
return option.None[T]()
22+
}
23+
24+
// Otherwise get the currently active iterator and ask it for a value
25+
currentIterator := iter.iterators[iter.iteratorIndex]
26+
value, ok := currentIterator.Next().Value()
27+
28+
// If there is a value then emit it
29+
if ok {
30+
return option.Some(value)
31+
}
32+
33+
// Otherwise the iterator has been exhausted, so increase the iterator index for the next
34+
// iteration of the loop.
35+
iter.iteratorIndex = iter.iteratorIndex + 1
36+
}
37+
38+
}
39+
40+
var _ Iterator[struct{}] = new(ChainIter[struct{}])

iter/chain_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package iter_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/BooleanCat/go-functional/internal/assert"
8+
"github.com/BooleanCat/go-functional/iter"
9+
)
10+
11+
func ExampleChain() {
12+
fmt.Println(iter.Collect[int](iter.Chain[int](iter.Lift([]int{1, 2}), iter.Lift([]int{3, 4}), iter.Lift([]int{0, 9}))))
13+
// Output: [1 2 3 4 0 9]
14+
}
15+
16+
func TestChainMultiple(t *testing.T) {
17+
items := iter.Chain[int](iter.Lift([]int{1, 2}), iter.Lift([]int{3, 4}))
18+
assert.Equal(t, items.Next().Unwrap(), 1)
19+
assert.Equal(t, items.Next().Unwrap(), 2)
20+
assert.Equal(t, items.Next().Unwrap(), 3)
21+
assert.Equal(t, items.Next().Unwrap(), 4)
22+
assert.True(t, items.Next().IsNone())
23+
}
24+
25+
func TestChainSingle(t *testing.T) {
26+
items := iter.Chain[int](iter.Lift([]int{1, 2}))
27+
assert.Equal(t, items.Next().Unwrap(), 1)
28+
assert.Equal(t, items.Next().Unwrap(), 2)
29+
assert.True(t, items.Next().IsNone())
30+
}
31+
32+
func TestChainEmpty(t *testing.T) {
33+
assert.True(t, iter.Chain[int]().Next().IsNone())
34+
}

0 commit comments

Comments
 (0)