Skip to content

Commit baa7be0

Browse files
committed
Add Compact iterator
1 parent 080c646 commit baa7be0

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,19 @@ for number := range itx.FromChannel(items).Exclude(filter.IsZero) {
431431
> In order to prevent a deadlock, the channel must be closed before attemping to stop the iterator
432432
> when it's used in a pull style. See [iter.Pull](https://pkg.go.dev/iter#Pull).
433433
434+
### Compact
435+
436+
Compact yields all values from a delegate iterator that are not zero values. It is functionally
437+
equivalent to `it.Filter(delegate, filter.IsZero)`.
438+
439+
```go
440+
words := it.Compact(slices.Values([]string{"foo", "", "bar", "", ""}))
441+
```
442+
443+
<!-- prettier-ignore -->
444+
> [!NOTE]
445+
> The `itx` package does not contain `Compact` due to limitations with Go's type system.
446+
434447
### Cycle
435448

436449
Cycle yields all values from an iterator before returning to the beginning and yielding all values

it/compact.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package it
2+
3+
import "iter"
4+
5+
// Compact yields all values from a delegate iterator that are not zero values.
6+
func Compact[V comparable](delegate func(func(V) bool)) iter.Seq[V] {
7+
return func(yield func(V) bool) {
8+
for value := range delegate {
9+
var zero V
10+
if zero == value {
11+
continue
12+
}
13+
14+
if !yield(value) {
15+
return
16+
}
17+
}
18+
}
19+
}

it/compact_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package it_test
2+
3+
import (
4+
"fmt"
5+
"slices"
6+
"testing"
7+
8+
"github.com/BooleanCat/go-functional/v2/internal/assert"
9+
"github.com/BooleanCat/go-functional/v2/it"
10+
)
11+
12+
func ExampleCompact() {
13+
words := slices.Values([]string{"", "foo", "", "", "bar", ""})
14+
fmt.Println(slices.Collect(it.Compact(words)))
15+
// Output: [foo bar]
16+
}
17+
18+
func TestCompactEmpty(t *testing.T) {
19+
t.Parallel()
20+
21+
words := slices.Collect(it.Compact(it.Exhausted[string]()))
22+
assert.Empty[string](t, words)
23+
}
24+
25+
func TestCompactOnlyEmpty(t *testing.T) {
26+
t.Parallel()
27+
28+
words := slices.Values([]string{"", "", "", ""})
29+
assert.Empty[string](t, slices.Collect(it.Compact(words)))
30+
}
31+
32+
func TestCompactOnlyNotEmpty(t *testing.T) {
33+
t.Parallel()
34+
35+
words := slices.Values([]string{"foo", "bar"})
36+
assert.SliceEqual(t, slices.Collect(it.Compact(words)), []string{"foo", "bar"})
37+
}
38+
39+
func TestCompactYieldFalse(t *testing.T) {
40+
t.Parallel()
41+
42+
words := it.Compact(slices.Values([]string{"foo", "bar"}))
43+
44+
words(func(string) bool {
45+
return false
46+
})
47+
}

0 commit comments

Comments
 (0)