Skip to content

Commit

Permalink
Add TryCollect and Collect2 consumers and remove CollectErr
Browse files Browse the repository at this point in the history
  • Loading branch information
BooleanCat committed Jul 27, 2024
1 parent cc19074 commit 7eaa52e
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 47 deletions.
22 changes: 22 additions & 0 deletions it/enumerate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package it_test
import (
"fmt"
"slices"
"testing"

"github.com/BooleanCat/go-functional/v2/internal/assert"
"github.com/BooleanCat/go-functional/v2/it"
)

Expand All @@ -17,3 +19,23 @@ func ExampleEnumerate() {
// 1 2
// 2 3
}

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

iterator := it.Enumerate(slices.Values([]int{1, 2, 3, 4, 5}))

var (
index int
number int
)

iterator(func(i int, n int) bool {
index = i
number = n
return false
})

assert.Equal(t, index, 0)
assert.Equal(t, number, 1)
}
22 changes: 0 additions & 22 deletions it/exhausted_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import (
"fmt"
"maps"
"slices"
"testing"

"github.com/BooleanCat/go-functional/v2/internal/assert"
"github.com/BooleanCat/go-functional/v2/it"
)

Expand All @@ -19,23 +17,3 @@ func ExampleExhausted2() {
fmt.Println(len(maps.Collect(it.Exhausted2[int, string]())))
// Output: 0
}

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

iterator := it.Enumerate(slices.Values([]int{1, 2, 3, 4, 5}))

var (
index int
number int
)

iterator(func(i int, n int) bool {
index = i
number = n
return false
})

assert.Equal(t, index, 0)
assert.Equal(t, number, 1)
}
34 changes: 24 additions & 10 deletions it/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package it

import (
"cmp"
"errors"
"iter"
)

Expand Down Expand Up @@ -127,20 +126,35 @@ func Find2[V, W any](iterator func(func(V, W) bool), pred func(V, W) bool) (V, W
return zeroV, zeroW, false
}

// CollectErr consumes an [iter.Seq2] where the right side yields errors and
// returns a slice of values and all errors joined together.
func CollectErr[V any](delegate func(func(V, error) bool)) ([]V, error) {
// TryCollect consumes an [iter.Seq2] where the right side yields errors and
// returns a slice of values and the first error encountered. Iteration stops
// at the first error.
func TryCollect[V any](iterator func(func(V, error) bool)) ([]V, error) {
var values []V

for v, err := range iterator {
if err != nil {
return values, err
}
values = append(values, v)
}

return values, nil
}

// Collect2 consumes an [iter.Seq2] and returns two slices of values.
func Collect2[V, W any](iterator func(func(V, W) bool)) ([]V, []W) {
var (
values []V
errs []error
lefts []V
rights []W
)

for v, err := range delegate {
values = append(values, v)
errs = append(errs, err)
for v, w := range iterator {
lefts = append(lefts, v)
rights = append(rights, w)
}

return values, errors.Join(errs...)
return lefts, rights
}

// Len consumes an [iter.Seq] and returns the number of values yielded.
Expand Down
38 changes: 30 additions & 8 deletions it/iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestForEachEmpty(t *testing.T) {
}

func ExampleForEach2() {
it.ForEach2(it.Enumerate(slices.Values([]int{1, 2, 3})), func(index int, number int) {
it.ForEach2(slices.All([]int{1, 2, 3}), func(index int, number int) {
fmt.Println(index, number)
})
// Output:
Expand Down Expand Up @@ -59,7 +59,7 @@ func TestReduceEmpty(t *testing.T) {
}

func ExampleReduce2() {
fmt.Println(it.Reduce2(it.Enumerate(slices.Values([]int{1, 2, 3})), func(i, a, b int) int {
fmt.Println(it.Reduce2(slices.All([]int{1, 2, 3}), func(i, a, b int) int {
return i + 1
}, 0))

Expand Down Expand Up @@ -115,7 +115,7 @@ func ExampleFind_notFound() {
}

func ExampleFind2() {
index, value, ok := it.Find2(it.Enumerate(slices.Values([]int{1, 2, 3})), func(i, v int) bool {
index, value, ok := it.Find2(slices.All([]int{1, 2, 3}), func(i, v int) bool {
return i == 2
})
fmt.Println(index, value, ok)
Expand All @@ -124,24 +124,46 @@ func ExampleFind2() {
}

func ExampleFind2_notFound() {
index, value, ok := it.Find2(it.Enumerate(slices.Values([]int{1, 2, 3})), func(i, v int) bool {
index, value, ok := it.Find2(slices.All([]int{1, 2, 3}), func(i, v int) bool {
return i == 4
})

fmt.Println(index, value, ok)
// Output: 0 0 false
}

func ExampleCollectErr() {
data := strings.NewReader("one\ntwo\nthree\n")
lines, err := it.CollectErr(it.LinesString(data))
func ExampleCollect2() {
indicies, values := it.Collect2(slices.All([]int{1, 2, 3}))
fmt.Println(values)
fmt.Println(indicies)

// Output:
// [1 2 3]
// [0 1 2]
}

func ExampleTryCollect() {
text := strings.NewReader("one\ntwo\nthree\n")

lines, err := it.TryCollect(it.LinesString(text))
fmt.Println(err)
fmt.Println(lines)

// Output:
// <nil>
// [one two three]
}

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

text := new(failSecondTime)
lines, err := it.TryCollect(it.LinesString(text))

assert.Equal(t, err.Error(), "read error")
assert.SliceEqual(t, lines, []string{"o"})
}

func ExampleLen() {
fmt.Println(it.Len(slices.Values([]int{1, 2, 3})))

Expand All @@ -155,7 +177,7 @@ func TestLenEmpty(t *testing.T) {
}

func ExampleLen2() {
fmt.Println(it.Len2(it.Enumerate(slices.Values([]int{1, 2, 3}))))
fmt.Println(it.Len2(slices.All([]int{1, 2, 3})))

// Output: 3
}
Expand Down
14 changes: 10 additions & 4 deletions it/itx/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,16 @@ func (iterator Iterator2[V, W]) Find(predicate func(V, W) bool) (V, W, bool) {
return it.Find2(iterator, predicate)
}

// CollectErr consumes an [Iterator2] where the right side yields errors and
// returns a slice of values and all errors yielded joined together.
func CollectErr[V any](iterator Iterator2[V, error]) ([]V, error) {
return it.CollectErr(iter.Seq2[V, error](iterator))
// TryCollect consumes an [iter.Seq2] where the right side yields errors and
// returns a slice of values and the first error encountered. Iteration stops
// at the first error.
func TryCollect[V any](iterator func(func(V, error) bool)) ([]V, error) {
return it.TryCollect(iterator)
}

// Collect2 consumes an [iter.Seq2] and returns two slices of values.
func (iterator Iterator2[V, W]) Collect() ([]V, []W) {
return it.Collect2(iterator)
}

// Len is a convenience method for chaining [it.Len] on [Iterator]s.
Expand Down
17 changes: 14 additions & 3 deletions it/itx/iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,27 @@ func ExampleFromMap() {
// Output: [2]
}

func ExampleCollectErr() {
data := strings.NewReader("one\ntwo\nthree\n")
lines, err := itx.CollectErr(itx.LinesString(data))
func ExampleTryCollect() {
text := strings.NewReader("one\ntwo\nthree\n")
lines, err := itx.TryCollect(itx.LinesString(text))
fmt.Println(err)
fmt.Println(lines)

// Output:
// <nil>
// [one two three]
}

func ExampleIterator2_Collect() {
indicies, values := itx.FromSlice([]int{1, 2, 3}).Enumerate().Collect()
fmt.Println(values)
fmt.Println(indicies)

// Output:
// [1 2 3]
// [0 1 2]
}

func ExampleIterator_Len() {
fmt.Println(itx.FromSlice([]int{1, 2, 3}).Len())
// Output: 3
Expand Down

0 comments on commit 7eaa52e

Please sign in to comment.