Skip to content

Commit

Permalink
Add Chain iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
BooleanCat committed Jun 2, 2024
1 parent f03603c commit cd3a796
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 1 deletion.
31 changes: 31 additions & 0 deletions iter/chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package iter

import "iter"

// Chain yields values from multiple iterators in sequence.
func Chain[V any](iterators ...iter.Seq[V]) iter.Seq[V] {
return func(yield func(V) bool) {
for _, iterator := range iterators {
iterator(yield)
}
}
}

// Chain is a convenience method for chaining [Chain] on [Iterator]s.
func (iterator Iterator[V]) Chain(iterators ...iter.Seq[V]) Iterator[V] {
return Iterator[V](Chain[V](append([]iter.Seq[V]{iter.Seq[V](iterator)}, iterators...)...))
}

// Chain2 yields values from multiple iterators in sequence.
func Chain2[V, W any](iterators ...iter.Seq2[V, W]) iter.Seq2[V, W] {
return func(yield func(V, W) bool) {
for _, iterator := range iterators {
iterator(yield)
}
}
}

// Chain is a convenience method for chaining [Chain2] on [Iterator2]s.
func (iterator Iterator2[V, W]) Chain(iterators ...iter.Seq2[V, W]) Iterator2[V, W] {
return Iterator2[V, W](Chain2(append([]iter.Seq2[V, W]{iter.Seq2[V, W](iterator)}, iterators...)...))
}
103 changes: 103 additions & 0 deletions iter/chain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package iter_test

import (
"fmt"
it "iter"
"testing"

"github.com/BooleanCat/go-functional/v2/future/maps"
"github.com/BooleanCat/go-functional/v2/future/slices"
"github.com/BooleanCat/go-functional/v2/internal/assert"
"github.com/BooleanCat/go-functional/v2/iter"
)

func ExampleChain() {
numbers := slices.Collect(iter.Chain(slices.Values([]int{1, 2}), slices.Values([]int{3, 4})))

fmt.Println(numbers)
// Output: [1 2 3 4]
}

func ExampleChain_method() {
numbers := iter.Iterator[int](slices.Values([]int{1, 2})).Chain(slices.Values([]int{3, 4})).Collect()

fmt.Println(numbers)
// Output: [1 2 3 4]
}

func TestChainEmpty(t *testing.T) {
t.Parallel()

assert.Empty[int](t, slices.Collect(iter.Chain[int]()))
}

func TestChainMany(t *testing.T) {
t.Parallel()

numbers := slices.Collect(iter.Chain(
slices.Values([]int{1, 2}),
iter.Take(iter.Drop(iter.Count[int](), 3), 2),
slices.Values([]int{5, 6}),
))

assert.SliceEqual(t, []int{1, 2, 3, 4, 5, 6}, numbers)
}

func TestChainTerminateEarly(t *testing.T) {
t.Parallel()

_, stop := it.Pull(iter.Chain(slices.Values([]int{1, 2}), slices.Values([]int{3, 4})))
stop()
}

func ExampleChain2() {
pairs := maps.Collect(iter.Chain2(maps.All(map[string]int{"a": 1}), maps.All(map[string]int{"b": 2})))

fmt.Println(len(pairs))
// Output: 2
}

func ExampleChain2_method() {
pairs := iter.Iterator2[string, int](maps.All(map[string]int{"a": 1})).Chain(maps.All(map[string]int{"b": 2}))

fmt.Println(len(maps.Collect(it.Seq2[string, int](pairs))))
// Output: 2
}

func TestChain2(t *testing.T) {
t.Parallel()

pairs := maps.Collect(iter.Chain2(maps.All(map[string]int{"a": 1}), maps.All(map[string]int{"b": 2})))

assert.Equal(t, 2, len(pairs))
assert.Equal(t, pairs["a"], 1)
assert.Equal(t, pairs["b"], 2)
}

func TestChain2Empty(t *testing.T) {
t.Parallel()

assert.Equal(t, len(maps.Collect(iter.Chain2[int, int]())), 0)
}

func TestChain2Many(t *testing.T) {
t.Parallel()

pairs := maps.Collect(iter.Chain2(
maps.All(map[string]int{"a": 1}),
maps.All(map[string]int{"b": 2}),
maps.All(map[string]int{"c": 3}),
))

assert.Equal(t, 3, len(pairs))
assert.Equal(t, pairs["a"], 1)
assert.Equal(t, pairs["b"], 2)
assert.Equal(t, pairs["c"], 3)
}

func TestChain2TerminateEarly(t *testing.T) {
t.Parallel()

_, stop := it.Pull2(iter.Chain2(maps.All(map[string]int{"a": 1})))
stop()
}
1 change: 0 additions & 1 deletion iter/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ func TestFromChannelEmpty(t *testing.T) {
close(channel)

assert.Empty[int](t, slices.Collect(iter.FromChannel(channel)))

}

func ExampleToChannel() {
Expand Down

0 comments on commit cd3a796

Please sign in to comment.