Skip to content

Commit

Permalink
feat(rangefunc): seq, seq2 (#28)
Browse files Browse the repository at this point in the history
feat(rangefunc): seq, seq2
  • Loading branch information
m4gshm authored Jul 1, 2024
1 parent 4ad83a5 commit a948190
Show file tree
Hide file tree
Showing 37 changed files with 1,409 additions and 162 deletions.
159 changes: 158 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@ result, err := slice.Conv(slice.Of("1", "3", "5", "_7", "9", "11"), strconv.Atoi
//[]int{1, 3, 5}, ErrSyntax
```

#### Slice converters

##### slice.Filter

``` go
Expand Down Expand Up @@ -454,9 +456,162 @@ var all, err = map_.Conv(employers, func(title string, employer map[string]strin
//map[d:Bob j:Tom], nil
```

## [seq](./seq/api.go), [seq2](./seq2/api.go)

API extends rangefunc iterator types `seq.Seq[V]`, `seq.Seq2[K,V]` with
utility functions kit.

``` go
even := func(i int) bool { return i%2 == 0 }
sequence := seq.Convert(seq.Filter(seq.Of(1, 2, 3, 4), even), strconv.Itoa)
var result []string = seq.Slice(sequence) //[2 4]
```

or

``` go
intSeq := seq.Conv(seq.Of("1", "2", "3", "ddd4", "5"), strconv.Atoi)
ints, err := seq2.Slice(intSeq) //[1 2 3], invalid syntax
```

### Sequence API

To use any collection or loop as a rangefunc sequecne just call `All`
method of that one.

In many cases the API likes the
[loop](#loop-kvloop-and-breakable-versions-breakloop-breakkvloop) API.

#### Instantiators

##### seq.Of, seq2.Of, seq2.OfMap

``` go
import(
"github.com/m4gshm/gollections/seq"
"github.com/m4gshm/gollections/seq2"
)

var (
ints iter.Seq[int] = seq.Of(1, 2, 3)
pairs iter.Seq2[string, int] = seq2.OfMap(map[string]int{"first": 1, "second": 2, "third": 3})
)
```

#### Collectors

##### seq.Slice

``` go
filter := func(u User) bool { return u.age <= 30 }
names := seq.Slice(seq.Convert(seq.Filter(seq.Of(users...), filter), User.Name))
//[Bob Tom]
```

##### seq2.Group, seq2.Map

``` go
import (
"iter"

"github.com/m4gshm/gollections/expr/use"
"github.com/m4gshm/gollections/seq"
"github.com/m4gshm/gollections/seq2"
"github.com/m4gshm/gollections/slice"
"github.com/m4gshm/gollections/slice/sort"
)

var users iter.Seq[User] = seq.Of(users...)
var groups iter.Seq2[string, User] = seq.ToSeq2(users, func(u User) (string, User) {
return use.If(u.age <= 20, "<=20").If(u.age <= 30, "<=30").Else(">30"), u
})
var ageGroups map[string][]User = seq2.Group(groups)

//map[<=20:[{Tom 18 []}] <=30:[{Bob 26 []}] >30:[{Alice 35 []} {Chris 41 []}]]
```

#### Reducers

##### seq.Reduce

``` go
var sum = seq.Reduce(seq.Of(1, 2, 3, 4, 5, 6), func(i1, i2 int) int { return i1 + i2 })
//21
```

##### seq.ReduceOK

``` go
adder := func(i1, i2 int) int { return i1 + i2 }

sum, ok := seq.ReduceOK(seq.Of(1, 2, 3, 4, 5, 6), adder)
//21, true

emptyLoop := seq.Of[int]()
sum, ok = seq.ReduceOK(emptyLoop, adder)
//0, false
```

##### seq.First

``` go
import (
"github.com/m4gshm/gollections/predicate/more"
"github.com/m4gshm/gollections/seq"
)

result, ok := seq.First(seq.Of(1, 3, 5, 7, 9, 11), more.Than(5)) //7, true
```

#### Element converters

##### seq.Convert

``` go
var s []string = seq.Slice(seq.Convert(seq.Of(1, 3, 5, 7, 9, 11), strconv.Itoa))
//[]string{"1", "3", "5", "7", "9", "11"}
```

##### seq.Conv

``` go
result, err := seq2.Slice(seq.Conv(seq.Of("1", "3", "5", "_7", "9", "11"), strconv.Atoi))
//[]int{1, 3, 5}, ErrSyntax
```

#### Sequence converters

##### seq.Filter

``` go
import (
"github.com/m4gshm/gollections/predicate/exclude"
"github.com/m4gshm/gollections/predicate/one"
"github.com/m4gshm/gollections/seq"
)

var f1 = seq.Slice(seq.Filter(seq.Of(1, 3, 5, 7, 9, 11), one.Of(1, 7).Or(one.Of(11))))
//[]int{1, 7, 11}

var f2 = seq.Slice(seq.Filter(seq.Of(1, 3, 5, 7, 9, 11), exclude.All(1, 7, 11)))
//[]int{3, 5, 9}
```

##### seq.Flat

``` go
import (
"github.com/m4gshm/gollections/convert/as"
"github.com/m4gshm/gollections/seq"
)

var i []int = seq.Slice(seq.Flat(seq.Of([][]int{{1, 2, 3}, {4}, {5, 6}}...), as.Is))
//[]int{1, 2, 3, 4, 5, 6}
```

## [loop](./loop/api.go), [kv/loop](./kv/loop/api.go) and breakable versions [break/loop](./break/loop/api.go), [break/kv/loop](./break/kv/loop/api.go)

Low-level API for iteration based on next functions:
Legacy iterators API based on the following functions:

``` go
type (
Expand Down Expand Up @@ -641,6 +796,8 @@ result, err := loop.Conv(loop.Of("1", "3", "5", "_7", "9", "11"), strconv.Atoi).
//[]int{1, 3, 5}, ErrSyntax
```

#### Loop converters

##### loop.Filter

``` go
Expand Down
6 changes: 3 additions & 3 deletions break/loop/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func ReduceeOK[T any](next func() (T, bool, error), merge func(T, T) (T, error))
if result, ok, err = next(); err != nil || !ok {
return result, ok, err
}
result, err = Accumm(result, next, merge)
result, err = Accumm(result, next, merge)
return result, true, err
}

Expand Down Expand Up @@ -402,7 +402,7 @@ func ConvertAndFilter[From, To any](next func() (From, bool, error), converter f
return FilterConvertFilter(next, always.True[From], converter, filter)
}

// Flatt creates a loop that extracts slices of 'To' by the 'flattener' function from iterable elements of 'From' and flattens as one iterable collection of 'To' elements.
// Flatt converts a two-dimensional loop in an one-dimensional one.
func Flatt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error)) Loop[To] {
if next == nil {
return nil
Expand Down Expand Up @@ -438,7 +438,7 @@ func Flatt[From, To any](next func() (From, bool, error), flattener func(From) (
}
}

// Flat creates a loop that extracts slices of 'To' by the 'flattener' function from iterable elements of 'From' and flattens as one iterable collection of 'To' elements.
// Flat converts a two-dimensional loop in an one-dimensional one.
func Flat[From, To any](next func() (From, bool, error), flattener func(From) []To) Loop[To] {
if next == nil {
return nil
Expand Down
2 changes: 1 addition & 1 deletion internal/benchmark/loop/collection2/loop_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,4 @@ func Benchmark_Loop_Slice_Loop_NextNext(b *testing.B) {
}
})
}
}
}
1 change: 0 additions & 1 deletion internal/benchmark/loop/loop/loop_range_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ func Benchmark_Slice_Iter_Iterating2(b *testing.B) {
}
}


func Benchmark_Slice_Mutable_Iter_Iterating(b *testing.B) {
integers := slice.Range(0, max)
for _, casee := range cases {
Expand Down
8 changes: 4 additions & 4 deletions internal/benchmark/loop/over_vs_loop/over_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

"github.com/m4gshm/gollections/loop"
"github.com/m4gshm/gollections/loop/range_"
"github.com/m4gshm/gollections/over"
"github.com/m4gshm/gollections/seq"
)

var max = 100000
Expand Down Expand Up @@ -36,7 +36,7 @@ func Benchmark_loop_Converted_All(b *testing.B) {
func Benchmark_over_Converted(b *testing.B) {
integers := range_.Of(0, max)
for i := 0; i < b.N; i++ {
for element := range over.Converted(integers.All, strconv.Itoa) {
for element := range seq.Convert(integers.All, strconv.Itoa) {
resultStr = element
}
}
Expand All @@ -45,7 +45,7 @@ func Benchmark_over_Converted(b *testing.B) {
func Benchmark_over_Converted_direct(b *testing.B) {
integers := range_.Of(0, max)
for i := 0; i < b.N; i++ {
over.Converted(integers.All, strconv.Itoa)(func(element string) bool {
seq.Convert(integers.All, strconv.Itoa)(func(element string) bool {
resultStr = element
return true
})
Expand Down Expand Up @@ -77,7 +77,7 @@ func Benchmark_loop_Convert_Filtered_rangefunc(b *testing.B) {
func Benchmark_over_Convert_Filtered(b *testing.B) {
integers := range_.Of(0, max)
for i := 0; i < b.N; i++ {
for element := range over.Converted(over.Filtered(integers.All, even), strconv.Itoa) {
for element := range seq.Convert(seq.Filter(integers.All, even), strconv.Itoa) {
resultStr = element
}
}
Expand Down
106 changes: 105 additions & 1 deletion internal/docs/readme.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ include::../examples/sliceexamples/slice_Convert_test.go[lines=13..16,indent=0]
----
include::../examples/sliceexamples/slice_Conv_test.go[lines=13..16,indent=0]
----
===== Slice converters
====== slice.Filter
[source,go]
----
Expand Down Expand Up @@ -266,10 +267,112 @@ include::../examples/mapexamples/map_Convert_test.go[lines=17..22,indent=0]
include::../examples/mapexamples/map_Conv_test.go[lines=17..22,indent=0]
----

[#seq]
=== link:./seq/api.go[seq], link:./seq2/api.go[seq2]

API extends rangefunc iterator types `seq.Seq[V]`, `seq.Seq2[K,V]` with utility functions kit.

[source,go]
----
include::../examples/seqexamples/seq_filter_convert_reduce_test.go[lines=13..17,indent=0]
----
or
[source,go]
----
include::../examples/seqexamples/seq2_filter_convert_reduce_test.go[lines=14..17,indent=0]
----
==== Sequence API

To use any collection or loop as a rangefunc sequecne just call `link:#iterating-over-loops[All]` method of that one.

In many cases the API likes the link:#loop-kvloop-and-breakable-versions-breakloop-breakkvloop[loop] API.

===== Instantiators
====== seq.Of, seq2.Of, seq2.OfMap
[source,go]
----
import(
"github.com/m4gshm/gollections/seq"
"github.com/m4gshm/gollections/seq2"
)
include::../examples/seqexamples/seq_Of_test.go[lines=14..19,indent=0]
----
===== Collectors
====== seq.Slice
[source,go]
----
include::../examples/seqexamples/seq_Slice_test.go[lines=12..16,indent=0]
----
====== seq2.Group, seq2.Map
[source,go]
----
import (
"iter"
"github.com/m4gshm/gollections/expr/use"
"github.com/m4gshm/gollections/seq"
"github.com/m4gshm/gollections/seq2"
"github.com/m4gshm/gollections/slice"
"github.com/m4gshm/gollections/slice/sort"
)
include::../examples/seqexamples/seq2_Group_test.go[lines=17..25,indent=0]
----
===== Reducers
====== seq.Reduce
[source,go]
----
include::../examples/seqexamples/seq_Reduce_test.go[lines=12..15,indent=0]
----
====== seq.ReduceOK
[source,go]
----
include::../examples/seqexamples/seq_ReduceOK_test.go[lines=12..21,indent=0]
----
====== seq.First
[source,go]
----
import (
"github.com/m4gshm/gollections/predicate/more"
"github.com/m4gshm/gollections/seq"
)
include::../examples/seqexamples/seq_First_test.go[lines=13..15,indent=0]
----
===== Element converters
====== seq.Convert
[source,go]
----
include::../examples/seqexamples/seq_Convert_test.go[lines=12..15,indent=0]
----
====== seq.Conv
[source,go]
----
include::../examples/seqexamples/seq_Conv_test.go[lines=14..17,indent=0]
----
===== Sequence converters
====== seq.Filter
[source,go]
----
import (
"github.com/m4gshm/gollections/predicate/exclude"
"github.com/m4gshm/gollections/predicate/one"
"github.com/m4gshm/gollections/seq"
)
include::../examples/seqexamples/seq_Filter.go[lines=14..20,indent=0]
----
====== seq.Flat
[source,go]
----
import (
"github.com/m4gshm/gollections/convert/as"
"github.com/m4gshm/gollections/seq"
)
include::../examples/seqexamples/seq_Flat_test.go[lines=13..16,indent=0]
----

[#loop]
=== link:./loop/api.go[loop], link:./kv/loop/api.go[kv/loop] and breakable versions link:./break/loop/api.go[break/loop], link:./break/kv/loop/api.go[break/kv/loop]

Low-level API for iteration based on next functions:
Legacy iterators API based on the following functions:

[source,go]
----
Expand Down Expand Up @@ -388,6 +491,7 @@ include::../examples/loopexamples/loop_Convert_test.go[lines=12..15,indent=0]
----
include::../examples/loopexamples/loop_Conv_test.go[lines=13..16,indent=0]
----
===== Loop converters
====== loop.Filter
[source,go]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/m4gshm/gollections/break/loop"
)

func Test_Slice_Vs_Loop(t *testing.T) {
func Test_Usage_Loop(t *testing.T) {

intSeq := loop.Conv(loop.Of("1", "2", "3", "ddd4", "5"), strconv.Atoi)
ints, err := loop.Slice(intSeq) //[1 2 3], invalid syntax
Expand Down
Loading

0 comments on commit a948190

Please sign in to comment.