Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
65f5ccb
lint: pin golangci-lint version
NathanBaulch Sep 23, 2025
697f99e
lint: fix issues triggered by go1.23 upgrade
NathanBaulch Sep 23, 2025
9de245a
feat: new iter package
NathanBaulch Sep 23, 2025
7a618c4
Merge branch 'master' into iter
NathanBaulch Sep 25, 2025
7233ad2
lint: fix linter issues
NathanBaulch Sep 25, 2025
d4bec61
fix: restore go1.18
NathanBaulch Sep 25, 2025
d81127b
fix: rename package to "it"
NathanBaulch Sep 25, 2025
400842c
feat: assign multiple sequences of maps
NathanBaulch Sep 25, 2025
e4a7fcd
fix: panic in DropRight if n = 0
NathanBaulch Sep 25, 2025
e40b12c
docs: fix incorrect non-iter helper references
NathanBaulch Sep 25, 2025
f8e7836
feat: implement Invert helper
NathanBaulch Sep 25, 2025
726ceae
feat: helpers for creating and checking empty sequences
NathanBaulch Sep 25, 2025
34ce242
feat: implement Reverse helper
NathanBaulch Sep 25, 2025
b15e32f
feat: implement ReduceRight helper
NathanBaulch Sep 25, 2025
e3175eb
feat: implement Shuffle helper
NathanBaulch Sep 25, 2025
80785df
feat: implement Sample* helpers
NathanBaulch Sep 26, 2025
97cff7a
refactor: rename helpers with Seq convention
NathanBaulch Sep 26, 2025
0287545
feat: implement SeqToChannel2 helper
NathanBaulch Sep 26, 2025
e24e60f
feat: implement HasPrefix/HasSuffix helpers
NathanBaulch Sep 26, 2025
45b9bf1
Merge branch 'master' into iter
NathanBaulch Oct 2, 2025
b5fdb9c
chore: port recent changes
NathanBaulch Sep 29, 2025
0313ccd
perf: only iterate collection once in Every
NathanBaulch Sep 30, 2025
e1fd821
refactor: reduce dupe code by reusing helpers internally
NathanBaulch Sep 30, 2025
b5d4229
perf: reuse internal Mode slice
NathanBaulch Sep 30, 2025
44e77a4
feat: implement Length helper
NathanBaulch Sep 30, 2025
74c337a
chore: duplicate unit tests for *I helpers
NathanBaulch Sep 30, 2025
45e6b32
fix: omit duplicates in second Intersect list
NathanBaulch Sep 30, 2025
f53c472
feat: intersect more than 2 sequences
NathanBaulch Sep 30, 2025
a0dd596
feat: implement Drain helper
NathanBaulch Sep 30, 2025
4f5d649
feat: implement Seq/Seq2 conversion helpers
NathanBaulch Sep 30, 2025
9c65aef
refactor: rename *Right* to *Last*
NathanBaulch Sep 30, 2025
2601458
chore: minor cleanup
NathanBaulch Sep 30, 2025
6501399
refactor: consistent predicate/transform parameter names
NathanBaulch Sep 30, 2025
b2c748c
perf: abort Slice/Subset once upper bound reached
NathanBaulch Sep 30, 2025
5d136cc
refactor: rename IsSortedByKey to IsSortedBy
NathanBaulch Oct 1, 2025
6d1bc82
refactor: reuse more helpers internally
NathanBaulch Oct 1, 2025
8d6d8aa
feat: implement Cut* helpers
NathanBaulch Oct 1, 2025
d28f761
feat: implement Trim* helpers
NathanBaulch Oct 1, 2025
637fc26
perf: reduce allocations
NathanBaulch Oct 2, 2025
98b94ba
docs: describe iteration and allocation expectations
NathanBaulch Oct 2, 2025
d2aa9b3
Update .github/workflows/lint.yml
samber Oct 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package lo

import (
"context"
"math/rand"
"testing"
"time"

Expand Down Expand Up @@ -117,9 +116,6 @@ func TestDispatchingStrategyRandom(t *testing.T) {
testWithTimeout(t, 10*time.Millisecond)
is := assert.New(t)

// with this seed, the order of random channels are: 1 - 0
rand.Seed(14)

children := createChannels[int](2, 2)
rochildren := channelsToReadOnly(children)
defer closeChannels(children)
Expand Down
6 changes: 2 additions & 4 deletions find_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestHasPrefix(t *testing.T) {

is.True(HasPrefix([]int{1, 2, 3, 4}, []int{1, 2}))
is.False(HasPrefix([]int{1, 2, 3, 4}, []int{42}))
is.True(HasPrefix([]int{1, 2, 3, 4}, nil))
}

func TestHasSuffix(t *testing.T) {
Expand All @@ -44,6 +45,7 @@ func TestHasSuffix(t *testing.T) {

is.True(HasSuffix([]int{1, 2, 3, 4}, []int{3, 4}))
is.False(HasSuffix([]int{1, 2, 3, 4}, []int{42}))
is.True(HasSuffix([]int{1, 2, 3, 4}, nil))
}

func TestFind(t *testing.T) {
Expand Down Expand Up @@ -721,8 +723,6 @@ func TestSample(t *testing.T) {
t.Parallel()
is := assert.New(t)

rand.Seed(time.Now().UnixNano())

result1 := Sample([]string{"a", "b", "c"})
result2 := Sample([]string{})

Expand All @@ -747,8 +747,6 @@ func TestSamples(t *testing.T) {
t.Parallel()
is := assert.New(t)

rand.Seed(time.Now().UnixNano())

result1 := Samples([]string{"a", "b", "c"}, 3)
result2 := Samples([]string{}, 3)

Expand Down
50 changes: 50 additions & 0 deletions it/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//go:build go1.23

package it

import (
"iter"

"github.com/samber/lo"
)

// SeqToChannel returns a read-only channel of collection elements.
func SeqToChannel[T any](bufferSize int, collection iter.Seq[T]) <-chan T {
ch := make(chan T, bufferSize)

go func() {
for item := range collection {
ch <- item
}

close(ch)
}()

return ch
}

// SeqToChannel2 returns a read-only channel of collection elements.
func SeqToChannel2[K, V any](bufferSize int, collection iter.Seq2[K, V]) <-chan lo.Tuple2[K, V] {
ch := make(chan lo.Tuple2[K, V], bufferSize)

go func() {
for k, v := range collection {
ch <- lo.Tuple2[K, V]{A: k, B: v}
}

close(ch)
}()

return ch
}

// ChannelToSeq returns a sequence built from channels items. Blocks until channel closes.
func ChannelToSeq[T any](ch <-chan T) iter.Seq[T] {
return func(yield func(T) bool) {
for item := range ch {
if !yield(item) {
return
}
}
}
}
60 changes: 60 additions & 0 deletions it/channel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//go:build go1.23

package it

import (
"maps"
"slices"
"testing"

"github.com/samber/lo"
"github.com/stretchr/testify/assert"
)

func TestSeqToChannel(t *testing.T) {
t.Parallel()
is := assert.New(t)

ch := SeqToChannel(2, values(1, 2, 3))

r1, ok1 := <-ch
r2, ok2 := <-ch
r3, ok3 := <-ch
is.True(ok1)
is.Equal(1, r1)
is.True(ok2)
is.Equal(2, r2)
is.True(ok3)
is.Equal(3, r3)

_, ok4 := <-ch
is.False(ok4)
}

func TestSeqToChannel2(t *testing.T) {
t.Parallel()
is := assert.New(t)

ch := SeqToChannel2(2, maps.All(map[string]int{"a": 1, "b": 2, "c": 3}))

r1, ok1 := <-ch
r2, ok2 := <-ch
r3, ok3 := <-ch
is.True(ok1)
is.True(ok2)
is.True(ok3)
is.ElementsMatch([]lo.Tuple2[string, int]{{A: "a", B: 1}, {A: "b", B: 2}, {A: "c", B: 3}}, []lo.Tuple2[string, int]{r1, r2, r3})

_, ok4 := <-ch
is.False(ok4)
}

func TestChannelToSeq(t *testing.T) {
t.Parallel()
is := assert.New(t)

ch := SeqToChannel(2, values(1, 2, 3))
items := ChannelToSeq(ch)

is.Equal([]int{1, 2, 3}, slices.Collect(items))
}
Loading
Loading