seqs

package module
v1.5.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 14, 2025 License: MIT Imports: 14 Imported by: 1

README

Seqs - functions for operating on and with Go iterable sequences

Go Reference Go Report Card Tests Coverage Status

This is seqs, a library for working with iterable sequences, a.k.a. iterators, introduced in Go 1.23 via the “range over function” language feature and the iter standard-library package.

This is an adaptation of github.com/bobg/go-generics/v3/iter. The central type in that package, iter.Of, was made obsolete with the introduction of Go iterators. This library provides operations on iterable sequences analogous to the ones on iter.Of in the old package. It combines those with the proposal for an x/exp/iter package.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Accum

func Accum[T, A any](inp iter.Seq[T], init A, f func(A, T) A) iter.Seq[A]

Accum repeatedly applies a function to the elements of an iterator and produces an iterator over the accumulated values. On each call, the function receives the accumulated value and the next element of the input iterator. The first call receives the initial value as the accumulated value.

Example
package main

import (
	"fmt"

	"github.com/bobg/seqs"
)

func main() {
	var (
		ints   = seqs.Ints(1, 1)     // All integers starting at 1
		first5 = seqs.Limit(ints, 5) // First 5 integers
		sums   = seqs.Accum(first5, 0, func(a, b int) int { return a + b })
	)
	for val := range sums {
		fmt.Println(val)
	}
}
Output:

1
3
6
10
15

func Accum2 added in v0.2.0

func Accum2[T, U, A any](inp iter.Seq2[T, U], init A, f func(A, T, U) A) iter.Seq[A]

Accum2 repeatedly applies a function to the elements of a pairwise iterator and produces an iterator over the accumulated values. On each call, the function receives the accumulated value and the next pair of elements from the input iterator. The first call receives the initial value as the accumulated value.

func Accum2x added in v0.2.0

func Accum2x[T, U, A any](inp iter.Seq2[T, U], init A, f func(A, T, U) (A, error)) (iter.Seq[A], *error)

Accum2x repeatedly applies a function to the elements of an iterator and produces an iterator over the accumulated values, plus a pointer to an error. On each call, the function receives the accumulated value and the next pair of elements from the input iterator. The first call receives the initial value as the accumulated value. If the function returns an error, Accum2x stops. The error pointer that Accum2x returns may be dereferenced to discover that error, but only after the output iterator is fully consumed.

func Accumx

func Accumx[T, A any](inp iter.Seq[T], init A, f func(A, T) (A, error)) (iter.Seq[A], *error)

Accumx repeatedly applies a function to the elements of an iterator and produces an iterator over the accumulated values, plus a pointer to an error. On each call, the function receives the accumulated value and the next element of the input iterator. The first call receives the initial value as the accumulated value. If the function returns an error, Accumx stops. The error pointer that Accumx returns may be dereferenced to discover that error, but only after the output iterator is fully consumed.

Example
package main

import (
	"fmt"
	"slices"
	"strconv"

	"github.com/bobg/seqs"
)

func main() {
	intstrs := slices.Values([]string{"1", "2", "3", "4", "5"})
	ints, errptr := seqs.Accumx(intstrs, 0, func(a int, s string) (int, error) {
		val, err := strconv.Atoi(s)
		return a + val, err
	})
	for sum := range ints {
		fmt.Println(sum)
	}
	if *errptr != nil {
		panic(*errptr)
	}
}
Output:

1
3
6
10
15

func Bytes

func Bytes(inp string) iter.Seq[byte]

Bytes returns an iterator over the bytes in a string.

Example
package main

import (
	"fmt"

	"github.com/bobg/seqs"
)

func main() {
	const s = "Hello世界"
	for b := range seqs.Bytes(s) {
		fmt.Println(b)
	}
}
Output:

72
101
108
108
111
228
184
150
231
149
140

func CheckEmpty added in v1.3.0

func CheckEmpty[T any](inp iter.Seq[T]) (iter.Seq[T], bool)

CheckEmpty tells whether the given iterator is empty. To determine whether it is, it consumes the first element of the iterator. It returns a copy of the original iterator (with any consumed element restored) and a boolean that is true for empty and false otherwise.

Example
package main

import (
	"fmt"

	"github.com/bobg/seqs"
)

func main() {
	var (
		ints  = seqs.Ints(1, 1) // All integers starting at 1
		empty = seqs.Empty[int] // No integers at all
	)

	ints, isEmpty := seqs.CheckEmpty(ints) // Reassign ints to get an iterator that preserves the first value of the original ints
	fmt.Printf("ints is empty: %t\n", isEmpty)

	empty, isEmpty = seqs.CheckEmpty(empty) // Reassign empty to get an iterator that preserves the first value of the original empty
	fmt.Printf("empty is empty: %t\n", isEmpty)

	_, _ = ints, empty // (silence linter "declared but not used" error)

}
Output:

ints is empty: false
empty is empty: true

func CheckEmpty2 added in v1.3.0

func CheckEmpty2[T, U any](inp iter.Seq2[T, U]) (iter.Seq2[T, U], bool)

CheckEmpty2 tells whether the given iterator is empty. To determine whether it is, it consumes the first pair from the iterator. It returns a copy of the original iterator (with any consumed pair restored) and a boolean that is true for empty and false otherwise.

func CommBoth added in v1.2.0

func CommBoth[T cmp.Ordered](left, right iter.Seq[T]) iter.Seq[T]

CommBoth takes two ordered sequences and produces a sequence of elements that are in both left and right. For example, if left is [1, 2, 3, 4] and right is [2, 4, 6, 8], CommBoth produces [2, 4].

func CommBothFunc added in v1.2.0

func CommBothFunc[T any](left, right iter.Seq[T], cmp func(T, T) int) iter.Seq[T]

CommBothFunc is like CommBoth, but it uses a custom comparison function. The function cmp must return a negative value if its arguments are properly ordered, a positive value if they are reversed, and zero if they are equal.

func CommLeft added in v1.2.0

func CommLeft[T cmp.Ordered](left, right iter.Seq[T]) iter.Seq[T]

CommLeft takes two ordered sequences and produces a sequence of elements that are in left but not in right. For example, if left is [1, 2, 3, 4] and right is [2, 4, 6, 8], CommLeft produces [1, 3].

func CommLeftFunc added in v1.2.0

func CommLeftFunc[T any](left, right iter.Seq[T], cmp func(T, T) int) iter.Seq[T]

CommLeftFunc is like CommLeft, but it uses a custom comparison function. The function cmp must return a negative value if its arguments are properly ordered, a positive value if they are reversed, and zero if they are equal.

func CommRight added in v1.2.0

func CommRight[T cmp.Ordered](left, right iter.Seq[T]) iter.Seq[T]

CommRight takes two ordered sequences and produces a sequence of elements that are in right but not in left. For example, if left is [1, 2, 3, 4] and right is [2, 4, 6, 8], CommRight produces [6, 8].

func CommRightFunc added in v1.2.0

func CommRightFunc[T any](left, right iter.Seq[T], cmp func(T, T) int) iter.Seq[T]

CommRightFunc is like CommRight, but it uses a custom comparison function. The function cmp must return a negative value if its arguments are properly ordered, a positive value if they are reversed, and zero if they are equal.

func Compare

func Compare[T cmp.Ordered](a, b iter.Seq[T]) int

Compare performs an elementwise comparison of two sequences. It returns the result of cmp.Compare on the first pair of unequal elements. If a ends before b, Compare returns -1. If b ends before a, Compare returns 1. If the sequences are equal, Compare returns 0.

Compare consumes as much of the input sequences as necessary to determine the result. If the sequences are equal and infinite, Compare will not terminate.

func CompareFunc

func CompareFunc[T any](a, b iter.Seq[T], f func(T, T) int) int

CompareFunc performs an elementwise comparison of two sequences, using a custom comparison function. The function should return a negative number if the first argument is less than the second, a positive number if the first argument is greater than the second, and zero if the arguments are equal.

CompareFunc returns the result of f on the first pair of unequal elements. If a ends before b, CompareFunc returns -1. If b ends before a, CompareFunc returns 1. If the sequences are equal, CompareFunc returns 0.

CompareFunc consumes as much of the input sequences as necessary to determine the result. If the sequences are equal and infinite, CompareFunc will not terminate.

func Concat

func Concat[T any](seqs ...iter.Seq[T]) iter.Seq[T]

Concat returns an iterator over the concatenation of the input sequences.

func Concat2

func Concat2[T, U any](seqs ...iter.Seq2[T, U]) iter.Seq2[T, U]

Concat2 returns an iterator over the concatenation of the sequences.

func Drain

func Drain[T any](inp iter.Seq[T]) int

Drain consumes all the elements of a sequence and returns the number of elements consumed. If the sequence is infinite, Drain will not terminate.

func Drain2

func Drain2[T, U any](inp iter.Seq2[T, U]) int

Drain2 consumes all the elements of a sequence and returns the number of elements consumed. If the sequence is infinite, Drain2 will not terminate.

func Dup

func Dup[T any](inp iter.Seq[T], n int) []iter.Seq[T]

Dup duplicates the contents of an iterator, producing n new iterators, each containing the members of the original.

An internal buffer grows to roughly the size of the difference between the output iterator that is farthest ahead in the stream, and the one that is farthest behind.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	var (
		ints       = seqs.Ints(1, 1)      // All integers starting at 1
		first10    = seqs.Limit(ints, 10) // First 10 integers
		dups       = seqs.Dup(first10, 2) // Two copies of the first10 iterator
		evens      = seqs.Filter(dups[0], func(val int) bool { return val%2 == 0 })
		odds       = seqs.Filter(dups[1], func(val int) bool { return val%2 == 1 })
		evensSlice = slices.Collect(evens)
		oddsSlice  = slices.Collect(odds)
	)
	fmt.Println(evensSlice)
	fmt.Println(oddsSlice)
}
Output:

[2 4 6 8 10]
[1 3 5 7 9]

func Empty

func Empty[T any](func(T) bool)

Empty is an empty sequence that can be used where an iter.Seq is expected. Usage note: you generally don't want to call this function, just refer to it as Empty[typename].

func Empty2

func Empty2[T, U any](func(T, U) bool)

Empty2 is an empty sequence that can be used where an iter.Seq2 is expected. Usage note: you generally don't want to call this function, just refer to it as Empty2[typename1, typename2].

func Enumerate

func Enumerate[T any](inp iter.Seq[T]) iter.Seq2[int, T]

Enumerate changes an iter.Seq to an iter.Seq2 of (index, val) pairs.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	var (
		strs = slices.Values([]string{"a", "b", "c"})
		seq  = seqs.Enumerate(strs)
	)
	for i, s := range seq {
		fmt.Println(i, s)
	}
}
Output:

0 a
1 b
2 c

func Equal added in v0.2.0

func Equal[T comparable](x, y iter.Seq[T]) bool

Equal reports whether the two sequences are equal. It consumes elements from both sequences until one of them is exhausted, or until it finds a pair of elements that are not equal. If the sequences are equal and infinite, Equal will not terminate.

func Equal2 added in v0.2.0

func Equal2[T, U comparable](x, y iter.Seq2[T, U]) bool

Equal2 reports whether the two sequences are equal. It consumes pairs of elements from both sequences until one of them is exhausted, or until it finds a pair of element-pairs that are not equal. If the sequences are equal and infinite, Equal2 will not terminate.

func EqualFunc added in v0.2.0

func EqualFunc[T, U any](x iter.Seq[T], y iter.Seq[U], f func(T, U) bool) bool

EqualFunc reports whether the two sequences are equal according to the function f. It consumes elements from both sequences until one of them is exhausted, or until it finds a pair of elements that are not equal. If the sequences are equal and infinite, EqualFunc will not terminate.

func EqualFunc2 added in v0.2.0

func EqualFunc2[K1, V1, K2, V2 any](x iter.Seq2[K1, V1], y iter.Seq2[K2, V2], f func(K1, V1, K2, V2) bool) bool

EqualFunc2 reports whether the two sequences are equal according to the function f. It consumes pairs of elements from both sequences until one of them is exhausted, or until it finds a pair of element-pairs that are not equal. If the sequences are equal and infinite, EqualFunc2 will not terminate.

func Filter

func Filter[T any](seq iter.Seq[T], f func(T) bool) iter.Seq[T]

Filter returns an iterator over seq that includes only the values v for which f(v) is true.

func Filter2 added in v0.2.0

func Filter2[T, U any](seq iter.Seq2[T, U], f func(T, U) bool) iter.Seq2[T, U]

Filter2 returns an iterator over seq that includes only the pairs t,u for which f(t, u) is true.

func First deprecated added in v1.1.0

func First[T any](seq iter.Seq[T]) (T, bool)

First returns the first value of seq and true. If seq is empty, it returns the zero value of T and false.

Deprecated: This function can leak resources. Use iter.Pull instead.

func First2 deprecated added in v1.3.0

func First2[T, U any](seq iter.Seq2[T, U]) (T, U, bool)

First2 returns the first pair of values in seq, and true. If seq is empty, it returns the zero values of T and U, and false.

Deprecated: This function can leak resources. Use iter.Pull2 instead.

func From

func From[T any](items ...T) iter.Seq[T]

From creates an iterator over the given items.

func FromChan

func FromChan[T any](inp <-chan T) iter.Seq[T]

FromChan produces an iterator over the contents of a channel.

func FromChanContext

func FromChanContext[T any](ctx context.Context, inp <-chan T) (iter.Seq[T], *error)

FromChanContext produces an iterator over the contents of a channel. It stops at the end of the channel or when the given context is canceled.

The caller can dereference the returned error pointer to check for errors (such as context.Canceled or context.DeadlineExceeded), but only after iteration is done.

func FromPairs

func FromPairs[T, U any](inp iter.Seq[Pair[T, U]]) iter.Seq2[T, U]

FromPairs changes an iter.Seq of [Pair]s to an iter.Seq2.

func Go

func Go[T any](f func(chan<- T) error) (iter.Seq[T], *error)

Go runs a function in a goroutine and returns an iterator over the values it produces. The function receives a channel for producing values. The channel closes when the function exits.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	it, errptr := seqs.Go(func(ch chan<- int) error {
		ch <- 1
		ch <- 2
		ch <- 3
		return nil
	})
	slice := slices.Collect(it)
	if *errptr != nil {
		panic(*errptr)
	}
	fmt.Println(slice)
}
Output:

[1 2 3]

func Go2

func Go2[T, U any](f func(chan<- Pair[T, U]) error) (iter.Seq2[T, U], *error)

Go2 runs a function in a goroutine and returns an iterator over the pairs of values it produces. The function receives a channel for producing pairs. The channel closes when the function exits.

func Ints

func Ints(start, delta int) iter.Seq[int]

Ints produces an infinite iterator over integers beginning at start, with each element increasing by delta.

func Last added in v0.2.0

func Last[T any](inp iter.Seq[T]) (T, bool)

Last returns the last element of the input sequence and true. If the input is empty, Last returns the zero value of T instead, and false. Last consumes the entire input sequence. Beware of infinite input sequences!

func Last2 added in v0.2.0

func Last2[T, U any](inp iter.Seq2[T, U]) (lastT T, lastU U, ok bool)

Last2 returns the last pair of elements from the pairwise input sequence, and true. If the input is empty, Last2 returns the zero values of T and U instead, and false. Last2 consumes the entire input sequence. Beware of infinite input sequences!

func LastN

func LastN[T any](inp iter.Seq[T], n int) []T

LastN produces a slice containing the last n elements of the input (or all of the input, if there are fewer than n elements). LastN consumes the entire input sequence. Beware of infinite input sequences!

func Left

func Left[T, U any](inp iter.Seq2[T, U]) iter.Seq[T]

Left changes an iter.Seq2 to an iter.Seq by dropping the second value.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	var (
		pairs = []seqs.Pair[int, string]{{X: 1, Y: "a"}, {X: 2, Y: "b"}, {X: 3, Y: "c"}}
		seq   = seqs.FromPairs(slices.Values(pairs))
		nums  = seqs.Left(seq)
	)
	fmt.Println(slices.Collect(nums))
}
Output:

[1 2 3]

func Limit added in v0.2.0

func Limit[T any](seq iter.Seq[T], n int) iter.Seq[T]

Limit returns an iterator over the elements of seq that stops after n values (or when seq is exhausted, whichever comes first).

func Limit2 added in v0.2.0

func Limit2[T, U any](seq iter.Seq2[T, U], n int) iter.Seq2[T, U]

Limit returns an iterator over the elements of seq that stops after n pairs (or when seq is exhausted, whichever comes first).

func Lines

func Lines(r io.Reader) (iter.Seq[string], *error)

Lines produces an iterator over the text lines in r. This uses a bufio.Scanner and is subject to its default line-length limit (see https://pkg.go.dev/bufio#pkg-constants). See LongLines for an alternative that does not have this limit.

The caller can dereference the returned error pointer to check for errors but only after iteration is done.

func LongLines

func LongLines(r io.Reader) (iter.Seq[io.Reader], *error)

LongLines produces an iterator of readers, each delivering a single line of text from r. Unlike Lines, this does not use a bufio.Scanner and is not subject to its default line-length limit. Each reader must be fully consumed before the next one is available.

The caller can dereference the returned error pointer to check for errors but only after iteration is done.

func Map

func Map[T, U any](inp iter.Seq[T], f func(T) U) iter.Seq[U]

Map returns an iterator over the values of inp transformed by the function f.

func Map2 added in v0.2.0

func Map2[T1, U1, T2, U2 any](inp iter.Seq2[T1, U1], f func(T1, U1) (T2, U2)) iter.Seq2[T2, U2]

Map2 returns an iterator over the pairs of values of inp transformed by the function f.

func Map2x added in v0.2.0

func Map2x[T1, U1, T2, U2 any](inp iter.Seq2[T1, U1], f func(T1, U1) (T2, U2, error)) (iter.Seq2[T2, U2], *error)

Map2x is the extended form of Map2. It produces an iterator of values transformed from an input iterator by a mapping function. If the mapping function returns an error, iteration stops and the error is available by dereferencing the returned pointer.

func Mapx

func Mapx[T, U any](inp iter.Seq[T], f func(T) (U, error)) (iter.Seq[U], *error)

Mapx is the extended form of Map. It produces an iterator of values transformed from an input iterator by a mapping function. If the mapping function returns an error, iteration stops and the error is available by dereferencing the returned pointer.

func Merge

func Merge[T cmp.Ordered](x, y iter.Seq[T]) iter.Seq[T]

Merge merges two sequences of ordered values. Values appear in the output once for each time they appear in x and once for each time they appear in y. If the two input sequences are not ordered, the output sequence will not be ordered, but it will still contain every value from x and y exactly once.

Merge is equivalent to calling MergeFunc with cmp.Compare[T] as the ordering function.

func Merge2 added in v0.2.0

func Merge2[K cmp.Ordered, V any](x, y iter.Seq2[K, V]) iter.Seq2[K, V]

Merge2 merges two sequences of key-value pairs ordered by their keys. Pairs appear in the output once for each time they appear in x and once for each time they appear in y. If the two input sequences are not ordered by their keys, the output sequence will not be ordered by its keys, but it will still contain every pair from x and y exactly once.

Merge2 is equivalent to calling MergeFunc2 with cmp.Compare[K] as the ordering function.

func MergeAll added in v0.2.0

func MergeAll[T cmp.Ordered](seqs ...iter.Seq[T]) iter.Seq[T]

MergeAll merges zero or more ordered sequences into a single one.

func MergeAllFunc added in v0.2.0

func MergeAllFunc[T cmp.Ordered](inps []iter.Seq[T], f func(T, T) int) iter.Seq[T]

MergeAllFunc merges zero or more ordered sequences into a single one, using the ordering function f, which should return zero if its arguments are equal, a negative value if the arguments are in the proper order, and a positive value if they are in the reverse order.

func MergeFunc

func MergeFunc[T any](x, y iter.Seq[T], f func(T, T) int) iter.Seq[T]

MergeFunc merges two sequences of values ordered by the function f. Values appear in the output once for each time they appear in x and once for each time they appear in y. When equal values appear in both sequences, the output contains the values from x before the values from y. If the two input sequences are not ordered by f, the output sequence will not be ordered by f, but it will still contain every value from x and y exactly once.

The function f should return zero if its arguments are equal, a negative value if the arguments are in the proper order, and a positive value if they are in the reverse order.

func MergeFunc2 added in v0.2.0

func MergeFunc2[K, V any](x, y iter.Seq2[K, V], f func(K, K) int) iter.Seq2[K, V]

MergeFunc2 merges two sequences of key-value pairs ordered by the function f. Pairs appear in the output once for each time they appear in x and once for each time they appear in y. When pairs with equal keys appear in both sequences, the output contains the pairs from x before the pairs from y. If the two input sequences are not ordered by f, the output sequence will not be ordered by f, but it will still contain every pair from x and y exactly once.

The function f should return zero if its arguments are equal, a negative value if the arguments are in the proper order, and a positive value if they are in the reverse order.

func Pages

func Pages[T any](inp iter.Seq[T], pageSize int) iter.Seq[[]T]

Pages converts an iterator of items into an iterator of pages of items. Each page is a slice of up to pageSize items.

Example
package main

import (
	"fmt"

	"github.com/bobg/seqs"
)

func main() {
	var (
		ints    = seqs.Ints(1, 1)      // All integers starting at 1
		first10 = seqs.Limit(ints, 10) // First 10 integers
	)
	pages := seqs.Pages(first10, 3)
	for page := range pages {
		fmt.Println(page)
	}
}
Output:

[1 2 3]
[4 5 6]
[7 8 9]
[10]

func Peek added in v1.3.0

func Peek[T any](inp iter.Seq[T]) (T, bool, iter.Seq[T])

Peek returns the first value in the given iterator. If the iterator is empty, the returned boolean is false, otherwise it's true. The first value of the input iterator, if there is one, is consumed. The returned iterator is a copy of the original iterator with any consumed value restored.

Note: if the caller fails to consume the returned iterator, this function can leak resources. One good way to make sure this does not happen, if the iterator is unneeded, is to pass the iterator to Drain. Another is to call iter.Pull on it and immediately call the returned "stop" function.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	var (
		ints   = seqs.Ints(1, 1)     // All integers starting at 1
		first3 = seqs.Limit(ints, 3) // First three integers
	)

	peeked, ok, first3 := seqs.Peek(first3)
	if ok {
		all3 := slices.Collect(first3)
		fmt.Printf("Peeked value is %d, full sequence is %v\n", peeked, all3)
	} else {
		fmt.Println("Sequence is empty")
	}
}
Output:

Peeked value is 1, full sequence is [1 2 3]

func Peek2 added in v1.3.0

func Peek2[T, U any](inp iter.Seq2[T, U]) (T, U, bool, iter.Seq2[T, U])

Peek2 returns the first pair of values in the given iterator. If the iterator is empty, the returned boolean is false, otherwise it's true. The first pair of the input iterator, if there is one, is consumed. The returned iterator is a copy of the original iterator with any consumed pair restored.

Note: if the caller fails to consume the returned iterator, this function can leak resources. One good way to make sure this does not happen, if the iterator is unneeded, is to pass the iterator to Drain2. Another is to call iter.Pull2 on it and immediately call the returned "stop" function.

func Prepared

func Prepared[T any](ctx context.Context, stmt *sql.Stmt, args ...any) (iter.Seq[T], *error)

Prepared is like SQL but uses a prepared sql.Stmt instead of a database and string query. It is the caller's responsibility to close the statement.

The caller may check for errors by dereferencing the returned error pointer, but only after the iterator is fully consumed.

func Reduce added in v0.2.0

func Reduce[T, A any](inp iter.Seq[T], init A, f func(A, T) A) A

Reduce combines the values in inp using f. The result begins as init. Then for each value v in inp, it updates the result to be f(result, v). It returns the final result value.

For example, if iterating over inp yields v1, v2, v3, Reduce returns f(f(f(init, v1), v2), v3).

Reduce is equivalent to calling Last(Accum(inp, init, f)). It consumes the entire input sequence. Beware of infinite input!

func Reduce2 added in v0.2.0

func Reduce2[T, U, A any](inp iter.Seq2[T, U], init A, f func(A, T, U) A) A

Reduce2 combines the values in inp using f. The result begins as init. Then for each value pair t,u in inp, it updates the result to be f(result, t, u). It returns the final result value.

For example, if iterating over inp yields pairs t1,u1, t2,u2, t3,u3, Reduce2 returns f(f(f(init, t1, u1), t2, u2), t3, u3).

Reduce2 is equivalent to calling Last2(Accum2(inp, init, f)). It consumes the entire input sequence. Beware of infinite input!

func Reduce2x added in v0.2.0

func Reduce2x[T, U, A any](inp iter.Seq2[T, U], init A, f func(A, T, U) (A, error)) (A, error)

Reduce2x is the extended form of Reduce2. It combines the values in inp using f. The result begins as init. Then for each value pair t,u in inp, it updates the result to be f(result, t, u). It returns the final result value. If f returns an error, iteration stops and Reduce2x returns that error.

Reduce2x consumes the entire input sequence. Beware of infinite input!

func Reducex added in v0.2.0

func Reducex[T, A any](inp iter.Seq[T], init A, f func(A, T) (A, error)) (A, error)

Reducex is the extended form of Reduce. It combines the values in inp using f. The result begins as init. Then for each value v in inp, it updates the result to be f(result, v). It returns the final result value. If f returns an error, iteration stops and Reducex returns that error.

Reducex consumes the entire input sequence. Beware of infinite input!

func Repeat

func Repeat[T any](val T) iter.Seq[T]

Repeat produces an infinite iterator repeatedly containing the given value.

func Right[T, U any](inp iter.Seq2[T, U]) iter.Seq[U]

Right changes an iter.Seq2 to an iter.Seq by dropping the first value.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	var (
		pairs = []seqs.Pair[int, string]{{X: 1, Y: "a"}, {X: 2, Y: "b"}, {X: 3, Y: "c"}}
		seq   = seqs.FromPairs(slices.Values(pairs))
		strs  = seqs.Right(seq)
	)
	fmt.Println(slices.Collect(strs))
}
Output:

[a b c]

func Runes

func Runes(inp string) iter.Seq[rune]

Runes returns an iterator over the runes in a string. This is the same as Right(String(inp)).

Example
package main

import (
	"fmt"

	"github.com/bobg/seqs"
)

func main() {
	const s = "Hello世界"
	for r := range seqs.Runes(s) {
		fmt.Println(string(r))
	}
}
Output:

H
e
l
l
o
世
界

func SQL

func SQL[T any](ctx context.Context, db QueryerContext, query string, args ...any) (iter.Seq[T], *error)

SQL performs a query against db and returns the results as an iterator over items of type T.

If the query produces a single value per row, T may be any scalar type (bool, int, float, string) into which each row's value can be scanned. T may also be sql.Null for querying a single nullable column.

Otherwise T must be a struct type whose fields have the same types, in the same order, as the values being queried. The values produced by the iterator will be instances of that struct type, with fields populated by the queried values.

The caller may check for errors by dereferencing the returned error pointer, but only after the iterator is fully consumed.

func SkipN

func SkipN[T any](inp iter.Seq[T], n int) iter.Seq[T]

SkipN copies the input iterator to the output, skipping the first N elements.

func SkipN2

func SkipN2[T, U any](inp iter.Seq2[T, U], n int) iter.Seq2[T, U]

SkipN2 copies the input iterator to the output, skipping the first N elements.

func SkipUntil

func SkipUntil[T any](inp iter.Seq[T], f func(T) bool) iter.Seq[T]

SkipUntil copies the input iterator to the output, discarding the initial elements until the first one that causes f to return true. That element and the remaining elements of inp are included in the output, and f is not called again.

func String

func String(inp string) iter.Seq2[int, rune]

String produces an iter.Seq2 over position-rune pairs in a string. The position of each rune is measured in bytes from the beginning of the string.

Example
package main

import (
	"fmt"

	"github.com/bobg/seqs"
)

func main() {
	const s = "Hello世界"
	for i, r := range seqs.String(s) {
		fmt.Printf("%d %c\n", i, r)
	}
}
Output:

0 H
1 e
2 l
3 l
4 o
5 世
8 界

func ToChan

func ToChan[T any](inp iter.Seq[T]) <-chan T

ToChan launches a goroutine that consumes an iterator and sends its values to a channel.

func ToChanContext

func ToChanContext[T any](ctx context.Context, f iter.Seq[T]) (<-chan T, *error)

ToChanContext launches a goroutine that consumes an iterator and sends it values to a channel. It stops early when the context is canceled.

The caller can dereference the returned error pointer to check for errors (such as context.Canceled or context.DeadlineExceeded), but only after reaching the end of the channel.

func ToPairs

func ToPairs[T, U any](inp iter.Seq2[T, U]) iter.Seq[Pair[T, U]]

ToPairs changes an iter.Seq2 to an iter.Seq of [Pair]s.

func Uniq

func Uniq[T comparable](inp iter.Seq[T]) iter.Seq[T]

Uniq filters out duplicate values from a sequence, yielding only the first occurrence of each value.

Only adjacent duplicates are removed. For example, {1, 1, 2, 2, 2, 3} becomes {1, 2, 3}, but {1, 2, 1, 2, 3} remains {1, 2, 1, 2, 3}.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	var (
		nums = slices.Values([]int{1, 1, 2, 2, 2, 3})
		uniq = seqs.Uniq(nums)
	)
	fmt.Println(slices.Collect(uniq))
}
Output:

[1 2 3]

func UniqFunc

func UniqFunc[T any](inp iter.Seq[T], f func(T, T) bool) iter.Seq[T]

UniqFunc filters out duplicate values from a sequence. Two values a and b are considered duplicates if f(a, b) returns true.

Only adjacent duplicates are removed.

func Words

func Words(r io.Reader) (iter.Seq[string], *error)

Words produces an iterator over the words in r, as determined by bufio.ScanWords.

The caller can dereference the returned error pointer to check for errors but only after iteration is done.

func Zip

func Zip[V1, V2 any](x iter.Seq[V1], y iter.Seq[V2]) iter.Seq[Zipped[V1, V2]]

Zip returns an iterator that iterates x and y in parallel, yielding Zipped values of successive elements of x and y. If one sequence ends before the other, the iteration continues with Zipped values in which either Ok1 or Ok2 is false, depending on which sequence ended first.

Zip is a useful building block for adapters that process pairs of sequences. For example, Equal can be defined as:

func Equal[V comparable](x, y iter.Seq[V]) bool {
	for z := range Zip(x, y) {
		if z.Ok1 != z.Ok2 || z.V1 != z.V2 {
			return false
		}
	}
	return true
}

func Zip2 added in v0.2.0

func Zip2[K1, V1, K2, V2 any](x iter.Seq2[K1, V1], y iter.Seq2[K2, V2]) iter.Seq[Zipped2[K1, V1, K2, V2]]

Zip2 returns an iterator that iterates x and y in parallel, yielding Zipped2 values of successive elements of x and y. If one sequence ends before the other, the iteration continues with Zipped2 values in which either Ok1 or Ok2 is false, depending on which sequence ended first.

Zip2 is a useful building block for adapters that process pairs of sequences. For example, Equal2 can be defined as:

func Equal2[K, V comparable](x, y iter.Seq2[K, V]) bool {
	for z := range Zip2(x, y) {
		if z.Ok1 != z.Ok2 || z.K1 != z.K2 || z.V1 != z.V2 {
			return false
		}
	}
	return true
}

func ZipVals added in v0.2.0

func ZipVals[T, U any](t iter.Seq[T], u iter.Seq[U]) iter.Seq2[T, U]

Zip takes two iterators and produces a new iterator containing pairs of corresponding elements. If one input iterator ends before the other, Zip produces zero values of the appropriate type in constructing pairs.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/bobg/seqs"
)

func main() {
	var (
		letters = slices.Values([]string{"a", "b", "c", "d"})
		nums    = slices.Values([]int{1, 2, 3})
		pairs   = seqs.ZipVals(letters, nums)
	)
	for x, y := range pairs {
		fmt.Println(x, y)
	}
}
Output:

a 1
b 2
c 3
d 0

Types

type Pair

type Pair[T, U any] struct {
	X T
	Y U
}

Pair is a generic pair of values.

func LastN2 added in v0.3.0

func LastN2[T, U any](inp iter.Seq2[T, U], n int) []Pair[T, U]

LastN2 produces a slice containing the last n pairs of elements of the input (or all of the input, if there are fewer than n pairs). LastN2 consumes the entire input sequence. Beware of infinite input sequences!

type QueryerContext

type QueryerContext interface {
	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
}

QueryerContext is a minimal interface satisfied by *sql.DB and *sql.Tx (from database/sql).

type Zipped added in v0.2.0

type Zipped[V1, V2 any] struct {
	V1  V1
	Ok1 bool // whether V1 is present (if not, it will be zero)
	V2  V2
	Ok2 bool // whether V2 is present (if not, it will be zero)
}

A Zipped is a pair of zipped values, one of which may be missing, drawn from two different sequences.

type Zipped2 added in v0.2.0

type Zipped2[K1, V1, K2, V2 any] struct {
	K1  K1
	V1  V1
	Ok1 bool // whether K1, V1 are present (if not, they will be zero)
	K2  K2
	V2  V2
	Ok2 bool // whether K2, V2 are present (if not, they will be zero)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL