Documentation
¶
Overview ¶
Package seq provides utilities for working with Go 1.23+ iterator sequences.
Index ¶
- func Chain[V any](seqs ...iter.Seq[V]) iter.Seq[V]
- func Chain2[K any, V any](seqs ...iter.Seq2[K, V]) iter.Seq2[K, V]
- func Filter[V any](seq iter.Seq[V], predicate func(V) bool) iter.Seq[V]
- func Filter2[K any, V any](seq iter.Seq2[K, V], predicate func(K, V) bool) iter.Seq2[K, V]
- func FilterMap[V any, U any](seq iter.Seq[V], fn func(V) (U, bool)) iter.Seq[U]
- func FilterMap2[K any, V any, U any](seq iter.Seq2[K, V], fn func(K, V) (U, bool)) iter.Seq2[K, U]
- func Flatten[V any](seq iter.Seq[[]V]) iter.Seq[V]
- func Map[V any, U any](seq iter.Seq[V], fn func(V) U) iter.Seq[U]
- func Map2[K any, V any, U any](seq iter.Seq2[K, V], fn func(K, V) U) iter.Seq2[K, U]
- func Repeat[V any](v V) iter.Seq[V]
- func Skip[V comparable](seq iter.Seq[V], n uint) iter.Seq[V]
- func Skip2[K comparable, V any](seq iter.Seq2[K, V], n uint) iter.Seq2[K, V]
- func SkipWhile[V comparable](seq iter.Seq[V], predicate func(V) bool) iter.Seq[V]
- func SkipWhile2[K comparable, V any](seq iter.Seq2[K, V], predicate func(K, V) bool) iter.Seq2[K, V]
- func Sorted2[K cmp.Ordered, V any](m map[K]V) iter.Seq2[K, V]
- func Take[V comparable](seq iter.Seq[V], n uint) iter.Seq[V]
- func Take2[K comparable, V any](seq iter.Seq2[K, V], n uint) iter.Seq2[K, V]
- func TakeWhile[V comparable](seq iter.Seq[V], predicate func(V) bool) iter.Seq[V]
- func TakeWhile2[K comparable, V any](seq iter.Seq2[K, V], predicate func(K, V) bool) iter.Seq2[K, V]
- func Uniq[V comparable](seq iter.Seq[V]) iter.Seq[V]
- func Uniq2[K comparable, V any](seq iter.Seq2[K, V]) iter.Seq2[K, V]
- func ValuesErr[Slice ~[]E, E any](s Slice, err error) (iter.Seq[E], error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Chain ¶ added in v0.1.0
Chain takes two (or more) iterators and creates a new iterator over them in sequence.
The new iterator will iterate over values from each iterator in the order they are provided.
In other words, it links two iterators together, in a chain.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
users1 := slices.Values([]string{"alice", "bob"})
users2 := slices.Values([]string{"charlie", "dave"})
users := seq.Chain(users1, users2)
for user := range users {
fmt.Println(user)
}
}
Output: alice bob charlie dave
func Chain2 ¶ added in v0.1.0
Chain2 takes two (or more) iterators and creates a new iterator over them in sequence.
The new iterator will iterate over pairs from each iterator in the order they are provided.
In other words, it links two iterators together, in a chain.
Example ¶
package main
import (
"fmt"
"iter"
"maps"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
users1 := maps.All(map[string]string{"alice": "admin", "bob": "admin"})
users2 := maps.All(map[string]string{"bob": "user", "charlie": "manager"})
users := seq.Chain2(users1, users2)
printSorted(users)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: alice: admin bob: admin bob: user charlie: manager
func Filter ¶
Filter creates an iterator using a predicate to determine if a value should be yielded.
The returned iterator will yield only the values for which the predicate is true.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
numbers := slices.Values([]int{1, 2, 3, 4, 5})
oddFilter := func(n int) bool {
return n%2 == 1
}
oddNumbers := seq.Filter(numbers, oddFilter)
for n := range oddNumbers {
fmt.Println(n)
}
}
Output: 1 3 5
func Filter2 ¶
Filter2 creates an iterator using a predicate to determine if a pair should be yielded.
The returned iterator will yield only the pairs for which the predicate is true.
Example ¶
package main
import (
"fmt"
"iter"
"maps"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
users := maps.All(map[string]string{"alice": "admin", "bob": "user", "charlie": "manager", "dave": "manager"})
managerFilter := func(k string, v string) bool {
return len(k) > 3 && v == "manager"
}
managers := seq.Filter2(users, managerFilter)
printSorted(managers)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: charlie: manager dave: manager
func FilterMap ¶ added in v0.1.0
FilterMap creates an iterator that both filters and maps.
See Filter and Map for details.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
numbers := slices.Values([]int{1, 2, 3, 4, 5, 6})
// Filter odd numbers and double them
doubleIfOdd := func(n int) (int, bool) {
return n * 2, n%2 == 1
}
doubledOdd := seq.FilterMap(numbers, doubleIfOdd)
for n := range doubledOdd {
fmt.Println(n)
}
}
Output: 2 6 10
func FilterMap2 ¶ added in v0.1.0
FilterMap2 creates an iterator that both filters and maps.
See Filter2 and Map2 for details.
Example ¶
package main
import (
"fmt"
"iter"
"maps"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
salaries := maps.All(map[string]float64{"alice": 100000, "bob": 80000, "charlie": 120000, "dave": 50000})
// Give everyone with a salary under 100,000 credits a raise of 5%
// and produce a list of names and new salaries
raise := func(k string, v float64) (float64, bool) {
if v < 100000 {
return v * 1.05, true
}
return v, false
}
promotions := seq.FilterMap2(salaries, raise)
printSorted(promotions)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: bob: 84000 dave: 52500
func Flatten ¶
Flatten returns an iterator that yields all elements of each slice produced by the outer sequence. It takes a sequence of slices and "flattens" it into a sequence of individual elements.
The elements are yielded in order: first all elements from the first slice, then all elements from the second slice, and so on.
This is useful for processing nested data structures or combining results from multiple operations that return slices.
Example ¶
package main
import (
"fmt"
"iter"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
job1 := func() []string {
return []string{"foo", "bar"}
}
job2 := func() []string {
return []string{"baz"}
}
job3 := func() []string {
return []string{"bat", "qux", "quux"}
}
doJobs := func() iter.Seq[[]string] {
return slices.Values([][]string{job1(), job2(), job3()})
}
results := seq.Flatten(doJobs())
for result := range results {
fmt.Println(result)
}
}
Output: foo bar baz bat qux quux
func Map ¶ added in v0.1.0
Map creates an iterator that transforms values using a function.
The returned iterator will yield the transformed values.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
numbers := slices.Values([]int{1, 2, 3, 4, 5})
double := func(n int) int {
return n * 2
}
doubled := seq.Map(numbers, double)
for n := range doubled {
fmt.Println(n)
}
}
Output: 2 4 6 8 10
func Map2 ¶ added in v0.1.0
Map2 creates an iterator that transforms values of a pair using a function.
The returned iterator will yield the transformed values.
Example ¶
package main
import (
"fmt"
"iter"
"maps"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
users := maps.All(map[string]string{"alice": "admin", "bob": "user", "charlie": "manager", "dave": "manager"})
payGrades := map[string]int{"admin": 1000, "user": 500, "manager": 1500}
// Calculate salaries for each user based on their role
calculateSalary := func(k string, v string) int {
return payGrades[v]
}
salaries := seq.Map2(users, calculateSalary)
printSorted(salaries)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: alice: 1000 bob: 500 charlie: 1500 dave: 1500
func Repeat ¶ added in v0.1.0
Repeat creates an iterator that yields the same value over and over.
WARNING: This iterator will never terminate on its own.
Example ¶
package main
import (
"fmt"
"github.com/sagikazarmark/seq"
)
func main() {
meaningOfLife := seq.Repeat(42)
var i int
for n := range meaningOfLife {
fmt.Println(n)
i++
if i == 5 {
break
}
}
}
Output: 42 42 42 42 42
func Skip ¶ added in v0.1.0
Skip creates an iterator that skips values until n values are skipped or the end of the iterator is reached (whichever happens first).
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
fruits := slices.Values([]string{"apple", "banana", "cherry", "grape", "mango"})
skip3 := seq.Skip(fruits, 3)
for n := range skip3 {
fmt.Println(n)
}
}
Output: grape mango
func Skip2 ¶ added in v0.1.0
Skip2 creates an iterator that skips pairs until n pairs are skipped or the end of the iterator is reached (whichever happens first).
Example ¶
package main
import (
"fmt"
"iter"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
users := seq.Sorted2(map[string]string{"alice": "admin", "bob": "user", "charlie": "manager", "dave": "manager"})
skip2 := seq.Skip2(users, 2)
printSorted(skip2)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: charlie: manager dave: manager
func SkipWhile ¶ added in v0.1.0
SkipWhile creates an iterator that yields values based on a predicate.
It will evaluate the predicate on each value, and skip values while it evaluates true. After false is returned, the rest of the values are yielded.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
fruits := slices.Values([]string{"apple", "apricot", "acerola", "banana", "cherry", "grape", "mango"})
noAs := seq.SkipWhile(fruits, func(v string) bool { return v[0] == 'a' })
for n := range noAs {
fmt.Println(n)
}
}
Output: banana cherry grape mango
func SkipWhile2 ¶ added in v0.1.0
func SkipWhile2[K comparable, V any](seq iter.Seq2[K, V], predicate func(K, V) bool) iter.Seq2[K, V]
SkipWhile2 creates an iterator that yields pairs based on a predicate.
It will evaluate the predicate on each pair, and skip pairs while it evaluates true. After false is returned, the rest of the pairs are yielded.
Example ¶
package main
import (
"fmt"
"iter"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
users := seq.Sorted2(map[string]string{"alice": "admin", "bob": "admin", "charlie": "manager", "dave": "user"})
skipAdmins := func(k string, v string) bool {
return v == "admin"
}
afterAdmins := seq.SkipWhile2(users, skipAdmins)
printSorted(afterAdmins)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: charlie: manager dave: user
func Sorted2 ¶ added in v0.1.0
Sorted2 creates an iterator that yields pairs in a sorted order (by key).
Useful when you need to iterate over a map in a sorted order.
Example ¶
package main
import (
"fmt"
"github.com/sagikazarmark/seq"
)
func main() {
users := seq.Sorted2(map[string]string{"charlie": "manager", "bob": "user", "alice": "admin", "dave": "manager"})
for user, role := range users {
fmt.Printf("%s: %s\n", user, role)
}
}
Output: alice: admin bob: user charlie: manager dave: manager
func Take ¶ added in v0.1.0
Take creates an iterator that yields the first n values, or fewer if the underlying iterator ends sooner.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
fruits := slices.Values([]string{"apple", "banana", "cherry", "grape", "mango"})
first3 := seq.Take(fruits, 3)
for n := range first3 {
fmt.Println(n)
}
}
Output: apple banana cherry
func Take2 ¶ added in v0.1.0
Take2 creates an iterator that yields the first n pairs, or fewer if the underlying iterator ends sooner.
Example ¶
package main
import (
"fmt"
"iter"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
users := seq.Sorted2(map[string]string{"alice": "admin", "bob": "user", "charlie": "manager", "dave": "manager"})
first3 := seq.Take2(users, 3)
printSorted(first3)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: alice: admin bob: user charlie: manager
func TakeWhile ¶ added in v0.1.0
TakeWhile creates an iterator that yields values based on a predicate.
It will evaluate the predicate on each value, and yield values while it evaluates true. After false is returned, the rest of the values are ignored.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
fruits := slices.Values([]string{"apple", "apricot", "acerola", "banana", "cherry", "grape", "mango"})
startsWithA := seq.TakeWhile(fruits, func(v string) bool { return v[0] == 'a' })
for n := range startsWithA {
fmt.Println(n)
}
}
Output: apple apricot acerola
func TakeWhile2 ¶ added in v0.1.0
func TakeWhile2[K comparable, V any](seq iter.Seq2[K, V], predicate func(K, V) bool) iter.Seq2[K, V]
TakeWhile2 creates an iterator that yields pairs based on a predicate.
It will evaluate the predicate on each pair, and yield pairs while it evaluates true. After false is returned, the rest of the pairs are ignored.
Example ¶
package main
import (
"fmt"
"iter"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
users := seq.Sorted2(map[string]string{"alice": "admin", "bob": "admin", "charlie": "manager", "dave": "manager"})
firstAdmins := seq.TakeWhile2(users, func(k string, v string) bool { return v == "admin" })
printSorted(firstAdmins)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: alice: admin bob: admin
func Uniq ¶
func Uniq[V comparable](seq iter.Seq[V]) iter.Seq[V]
Uniq ensures only unique values are returned from a sequence.
Items are returned in the order they first appear.
Example ¶
package main
import (
"fmt"
"slices"
"github.com/sagikazarmark/seq"
)
func main() {
numbers := slices.Values([]int{1, 2, 2, 3, 1, 4, 3, 5})
unique := seq.Uniq(numbers)
for number := range unique {
fmt.Println(number)
}
}
Output: 1 2 3 4 5
func Uniq2 ¶
Uniq2 ensures only unique keys are returned from a sequence.
Note: You can achieve a similar effect using maps.Collect, but that requires loading the entire sequence into memory. Additionally, while maps.Collect returns the last seen value for each key, Uniq2 returns the first seen value for each key.
Example ¶
package main
import (
"fmt"
"iter"
"maps"
"sort"
"strings"
"github.com/sagikazarmark/seq"
)
func main() {
roles := seq.Chain2(
maps.All(map[string]string{"alice": "admin", "bob": "user"}),
maps.All(map[string]string{"alice": "user", "charlie": "user"}),
)
unique := seq.Uniq2(roles)
printSorted(unique)
}
// Maps are unordered, so we need to hack for examples
func printSorted[K any, V any](s iter.Seq2[K, V]) {
var output []string
for key, value := range s {
output = append(output, fmt.Sprintf("%v: %v\n", key, value))
}
sort.Strings(output)
fmt.Print(strings.Join(output, ""))
}
Output: alice: admin bob: user charlie: user
func ValuesErr ¶
ValuesErr returns an iterator that yields the slice elements in order, or an error if one was provided.
If err is not nil, ValuesErr returns (nil, err). If err is nil, it returns an iterator over the slice values.
This is useful for chaining operations without intermediate variables:
items, err := seq.ValuesErr(fetchItems())
if err != nil {
return err
}
for item := range items {
// process item
}
Instead of:
itemSlice, err := fetchItems()
if err != nil {
return err
}
items := slices.Values(itemSlice)
for item := range items {
// process item
}
Example (Error) ¶
package main
import (
"errors"
"fmt"
"github.com/sagikazarmark/seq"
)
func main() {
fn := func() ([]struct{}, error) {
return nil, errors.New("something went wrong")
}
_, err := seq.ValuesErr(fn())
if err != nil {
fmt.Println(err)
}
}
Output: something went wrong
Example (Ok) ¶
package main
import (
"fmt"
"github.com/sagikazarmark/seq"
)
func main() {
fn := func() ([]string, error) {
return []string{"apple", "banana", "cherry"}, nil
}
fruits, err := seq.ValuesErr(fn())
if err != nil {
panic(err)
}
for fruit := range fruits {
fmt.Println(fruit)
}
}
Output: apple banana cherry
Types ¶
This section is empty.