
I found myself missing map and filter constructs for some small things in Go, and here we are. Go 1.18 got generics, and I’ve admittedly not used them too much in real apps. Go 1.23 brought iterators.
The combo of these two makes map/filter pretty easy to create. They play nicely with the utilities in slices and maps.
This code is available on github with some tests.
Map and Map2
To map over an iter.Seq and iter.Seq2 respectively. Both of these take and return an iterator. Both range over the input iterator, apply a function, and call the yield callback with the resulting value.
package mapfilter
import (
"iter"
)
func Map[V, U any](seq iter.Seq[V], f func(V) U) iter.Seq[U] {
return func(yield func(U) bool) {
for v := range seq {
if !yield(f(v)) {
break
}
}
}
}
func Map2[K, V, O, U any](seq iter.Seq2[K, V], f func(K, V) (O, U)) iter.Seq2[O, U] {
return func(yield func(O, U) bool) {
for k, v := range seq {
if !yield(f(k, v)) {
break
}
}
}
}
Filter and Filter2
For filtering an iter.Seq and iter.Seq2 respectively. Both take and return an iterator. Both range over the input iterator, check the value with a filter function, then call the yield callback if the filter passes.
package mapfilter
import (
"iter"
)
func Filter[V any](seq iter.Seq[V], check func(V) bool) iter.Seq[V] {
return func(yield func(V) bool) {
for v := range seq {
if !check(v) {
continue
}
if !yield(v) {
break
}
}
}
}
func Filter2[K, V any](seq iter.Seq2[K, V], check func(K, V) bool) iter.Seq2[K, V] {
return func(yield func(K, V) bool) {
for k, v := range seq {
if !check(k, v) {
continue
}
if !yield(k, v) {
break
}
}
}
}