catena

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 31, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

README

catena

Lazy, fully typed sequence pipelines for Go — Kotlin-stdlib and LINQ ergonomics on top of iter.Seq, built on Go 1.27 generic methods.

Catena is Latin for "chain."

CI Go Reference

top := catena.FromSlice(orders).
    Filter(func(o Order) bool { return o.Paid }).
    TopNBy(10, func(o Order) int { return o.Amount })

byUser := catena.FromSlice(orders).FoldBy(
    func(o Order) UserID { return o.User },
    func(UserID) int { return 0 },
    func(sum int, o Order) int { return sum + o.Amount },
)
go get github.com/NerdMeNot/catena

Requires Go 1.27+ (generic methods). Zero dependencies.

Why

Go finally has the two pieces this needed — iter.Seq as a common iterator currency, and generic methods so a chain can change element type mid-flight. What was missing was a library willing to be precise about the things that make or break iterator code in practice. catena is built on three commitments:

  • Nothing is hidden. No reflect, no any in value position, no hidden goroutines, no hidden buffering. An operator that buffers says so in its doc comment, with its bound; a terminal that would hang on an infinite sequence is marked; every panic happens at construction, at the line that made the mistake.
  • The contracts are tested, not promised. Every exported operator is registered in a conformance harness that consumes it twice, runs it over infinite sources, breaks early and checks the producer's cleanup ran, and compares it against a hand-written loop. A completeness check parses the package and fails CI for any operator nothing registers. Statement coverage is 100%, enforced.
  • Slow only where Go is slow. Measured against the same pipelines hand-built from raw iter.Seq closures, catena meets or beats the raw mechanism on every path — the library adds nothing. What remains against a plain loop is the iterator protocol itself, quantified in docs/05-performance.md rather than waved at.

What it looks like in practice

Streams stay lazy until a terminal consumes them, and early termination propagates through any number of stages — Take(2) here computes exactly two squares:

catena.Generate(1, func(n int) int { return n * 2 }). // 1, 2, 4, 8, ... forever
    Map(func(n int) int { return n * n }).
    Take(2).
    Collect() // [1 4]

When elements can fail, the pipeline carries the errors and the consumer picks the policy — abort, gather, or skip:

nums := catena.FromSlice(lines).MapErr(strconv.Atoi)

vals, err  := nums.Collect()          // stop at the first bad line
vals, errs := nums.CollectAll()       // keep everything, report everything
vals       := nums.Ignore().Collect() // skip bad lines

Producers that own resources open them lazily inside the pipeline, so an unconsumed pipeline holds nothing and a downstream Take(3) still closes the rows — a pattern proven against the real database/sql stack in bake_test.go, and documented in docs/03-error-handling.md.

The operators worth switching for are the ones that change the memory class, not just the syntax:

Instead of Which costs
FoldBy GroupBy + fold per bucket 2.97 MB → 1.2 KB (bounded by keys, not elements)
TopNBy(10, sel) SortedDesc().Take(10) 4.1 MB → 1 KB, 28× faster (bounded heap)
DedupeBy DistinctBy on sorted input unbounded seen-set → O(1)

Performance, before you choose

Know the cost going in. Measured three ways — a hand-written loop, the same pipeline hand-built from raw iter.Seq closures, and catena (Apple M5 Max, Go 1.27, 100k elements):

Shape Hand loop Raw closures catena
4-stage pipeline (filter→map→filter→sum) 39µs 350µs 262µs
Sum 107µs 176µs 70µs
Contains 116µs 70µs

Two facts fall out of that table. First, catena adds nothing on top of Go's iterator mechanism — it meets or beats the raw-closure baseline on every measured path, so the only thing you give up is what iter.Seq itself costs. Second, that cost is real: against a plain loop doing trivial arithmetic, a pipeline runs ~6.6× slower — about 2.2ns per element per stage of closure-call overhead the compiler cannot flatten. If your loop body does anything beyond arithmetic — parses, allocates, touches a map or a socket — the per-element work buries the protocol overhead and the two versions converge.

And where an operator changes the memory class, catena is the faster spelling outright: FoldBy aggregates in 1.2 KB where GroupBy+fold allocates 2.97 MB, and TopNBy(10) is 28× faster than sort-and-take. The full story, with the code both ways so you can judge what the nanoseconds buy: docs/05-performance.md.

The shape of the library

Type What it is
Seq[T] lazy iter.Seq[T] with ~60 chainable methods; range works directly
Seq2[K, V] the stdlib pair currency; a bridge back to Seq, not a peer
Try[T] iter.Seq2[T, error]; error policy chosen by the consumer
List[T] eager []T with the mirrored operation set — generated, and conformance-checked to agree with AsSeq()

Interop is free in both directions: iter.Seq[T](s), s.Seq(), catena.From(anyPushIterator). Operations that constrain the element type (Distinct, Sorted, Sum, Max, …) are package functions, because a method on Seq[T any] may require nothing of T; the chain continues normally after them.

Documentation

  • Getting started — the five-minute tour
  • examples/ — runnable programs, from first pipeline to relational joins
  • Concepts — the contract system that makes operators predictable
  • Error handlingTry and resource-owning producers
  • Operator catalog — every operator with its costs
  • Performance — the three-way benchmarks, honestly
  • SPEC.md — the full design: every decision, and what was rejected

Status

v1.0.0 — the API is frozen. Anything removed or changed incompatibly waits for a major version. Changes are tracked in CHANGELOG.md.

Licensed under Apache-2.0.

Documentation

Overview

Package catena is a lazy, fully-typed sequence library for Go 1.27+, built on iter.Seq and generic methods.

The four types:

  • Seq[T]: lazy, single-pass by contract, possibly infinite.
  • Seq2[K, V]: the stdlib pairing currency; a bridge back to Seq, not a peer.
  • Try[T]: Seq2[T, error]; error policy is chosen by the consumer (Collect stops at the first error, CollectAll drains, Ignore skips).
  • List[T]: eager []T with the mirrored operation set.

Contracts every caller should know:

  • Treat every Seq as single-pass. Re-iterability depends entirely on the producer (see the constructor table). Once() is a development guard.
  • Nil sequences are empty: every method and package function accepts a nil receiver or argument and treats it as an empty sequence.
  • Invalid construction arguments (negative counts, zero step) panic at construction time with a "catena: " prefixed message. Nil callbacks are not defended and panic at first use.
  • Operators marked as buffering state their bound; terminals marked as full-drain hang on infinite input.
  • Map-returning terminals return Go maps: iteration order is undefined.
  • When a Try element carries a non-nil error, do not read the value.
  • Not safe for concurrent use; ToChan is the fan-out mechanism.
  • comparable-constrained functions panic at runtime if T is an interface type holding a non-comparable value (Go 1.20 semantics).
Example (LazyAcquisition)
package main

import (
	"bufio"
	"fmt"
	"strings"

	"github.com/NerdMeNot/catena"
)

// Lines adapts an io.Reader into a Try of its lines — the §7.7 pattern.
// The reader is wrapped lazily inside the closure: a sequence that is
// never consumed never reads, and early termination stops the scan.
func Lines(open func() (*strings.Reader, error)) catena.Try[string] {
	return func(yield func(string, error) bool) {
		r, err := open()
		if err != nil {
			yield("", err)
			return
		}
		sc := bufio.NewScanner(r)
		for sc.Scan() {
			if !yield(sc.Text(), nil) {
				return
			}
		}
		if err := sc.Err(); err != nil {
			yield("", err)
		}
	}
}

func main() {
	opened := 0
	logs := Lines(func() (*strings.Reader, error) {
		opened++
		return strings.NewReader("GET /a\nPOST /b\nGET /c\nGET /d"), nil
	})

	// Building the pipeline opens nothing.
	gets := logs.Ignore().
		Filter(func(l string) bool { return strings.HasPrefix(l, "GET ") }).
		Take(2)
	fmt.Println("opened after building:", opened)

	fmt.Println(gets.Collect())
	fmt.Println("opened after consuming:", opened)
}
Output:
opened after building: 0
[GET /a GET /c]
opened after consuming: 1

Index

Examples

Constants

View Source
const Version = "1.0.0"

Version is the library's version, kept in lockstep with release tags: the release workflow refuses to publish a tag that disagrees with it.

Variables

This section is empty.

Functions

func AssociateWith

func AssociateWith[T comparable, V any](s Seq[T], f func(T) V) map[T]V

AssociateWith maps each element to f(element); on duplicate elements the last value wins. ⚠ Full drain; map iteration order is undefined.

func Average

func Average[T Numeric](s Seq[T]) (float64, bool)

Average returns the mean, accumulating in float64; (0, false) on empty input. ⚠ Full drain.

func CollectMap

func CollectMap[K comparable, V any](s Seq2[K, V]) map[K]V

CollectMap drains a pair sequence into a map; on duplicate keys the last value wins. ⚠ Full drain; map iteration order is undefined.

func Contains

func Contains[T comparable](s Seq[T], v T) bool

Contains reports whether v occurs in s; stops at the first match.

func Equal

func Equal[T comparable](a, b Seq[T]) bool

Equal reports whether a and b yield the same elements in the same order. Consumes both sequences up to and including the first difference — fully when they are equal. b is consumed through iter.Pull (its cleanup always runs).

func IndexOf

func IndexOf[T comparable](s Seq[T], v T) int

IndexOf returns the index of the first occurrence of v; -1 if none.

func Join

func Join(s Seq[string], sep string) string

Join concatenates a string sequence with sep between elements. ⚠ Full drain.

func Max

func Max[T cmp.Ordered](s Seq[T]) (T, bool)

Max returns the largest element; NaN orders below everything (cmp.Compare). ⚠ Full drain.

func Min

func Min[T cmp.Ordered](s Seq[T]) (T, bool)

Min returns the smallest element; NaN orders below everything, so a NaN in the input is the minimum. ⚠ Full drain.

func MinMax

func MinMax[T cmp.Ordered](s Seq[T]) (min, max T, ok bool)

MinMax returns the smallest and largest elements in one pass. ⚠ Full drain.

func Product

func Product[T Numeric](s Seq[T]) T

Product multiplies the elements. Empty input yields 1, the multiplicative identity. ⚠ Full drain.

func Self

func Self[T any](v T) T

Self is the identity selector: catena.Flatten(s) is s.FlatMap(Self).

func Sum

func Sum[T Numeric](s Seq[T]) T

Sum adds the elements; integer overflow wraps like +. Empty input sums to 0. ⚠ Full drain.

func Tally

func Tally[T comparable](s Seq[T]) map[T]int

Tally counts occurrences per value. ⚠ Full drain; map iteration order is undefined.

func ToSet

func ToSet[T comparable](s Seq[T]) map[T]struct{}

ToSet drains the sequence into a set. ⚠ Full drain; map iteration order is undefined.

func TopN

func TopN[T cmp.Ordered](s Seq[T], n int) []T

TopN returns the n largest elements, sorted descending; equal elements retain encounter order. Memory is O(n). ⚠ Full drain. Panics if n is negative.

func Unzip

func Unzip[K, V any](s Seq2[K, V]) ([]K, []V)

Unzip drains a pair sequence into its two sides; nil slices for empty input. ⚠ Full drain; buffers both sides.

Types

type Integer

type Integer interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

Integer is the constraint for Range.

type List

type List[T any] []T

List is an eager []T with the mirrored operation set. []T(l) unwraps it with no copy.

func (List[T]) All

func (l List[T]) All(pred func(T) bool) bool

All mirrors Seq.All eagerly.

func (List[T]) Any

func (l List[T]) Any(pred func(T) bool) bool

Any mirrors Seq.Any eagerly.

func (List[T]) Append

func (l List[T]) Append(vals ...T) List[T]

Append returns a new List with vals appended. Unlike the built-in append, the result ALWAYS has a fresh backing array and never aliases l — consistent with every other List transform. Callers who want the built-in's amortized behavior can use it directly: List is a []T.

func (List[T]) AsSeq

func (l List[T]) AsSeq() Seq[T]

AsSeq returns a lazy, re-iterable view of the list. The list is not copied; mutations are visible to later iterations.

func (List[T]) Associate

func (l List[T]) Associate[K comparable, V any](f func(T) (K, V)) map[K]V

Associate mirrors Seq.Associate eagerly.

func (List[T]) At

func (l List[T]) At(i int) T

At returns the element at index i, panicking exactly like l[i] on an out-of-range index. O(1).

func (List[T]) AverageOf

func (l List[T]) AverageOf[N Numeric](sel func(T) N) (float64, bool)

AverageOf mirrors Seq.AverageOf eagerly.

func (List[T]) BottomNBy

func (l List[T]) BottomNBy[K cmp.Ordered](n int, sel func(T) K) []T

BottomNBy mirrors Seq.BottomNBy eagerly.

func (List[T]) Clone

func (l List[T]) Clone() List[T]

Clone returns a shallow copy with a fresh backing array.

func (List[T]) Collect

func (l List[T]) Collect() []T

Collect mirrors Seq.Collect eagerly. O(1)/exact-allocation override.

func (List[T]) Concat

func (l List[T]) Concat(others ...Seq[T]) List[T]

Concat mirrors Seq.Concat eagerly.

func (List[T]) Count

func (l List[T]) Count() int

Count mirrors Seq.Count eagerly. O(1)/exact-allocation override.

func (List[T]) CountWhere

func (l List[T]) CountWhere(pred func(T) bool) int

CountWhere mirrors Seq.CountWhere eagerly.

func (List[T]) DedupeBy

func (l List[T]) DedupeBy[K comparable](sel func(T) K) List[T]

DedupeBy mirrors Seq.DedupeBy eagerly.

func (List[T]) DistinctBy

func (l List[T]) DistinctBy[K comparable](sel func(T) K) List[T]

DistinctBy mirrors Seq.DistinctBy eagerly.

func (List[T]) DistinctWith

func (l List[T]) DistinctWith(eq func(a, b T) bool) List[T]

DistinctWith mirrors Seq.DistinctWith eagerly.

func (List[T]) Drain

func (l List[T]) Drain()

Drain mirrors Seq.Drain eagerly.

func (List[T]) Drop

func (l List[T]) Drop(n int) List[T]

Drop mirrors Seq.Drop eagerly.

func (List[T]) DropLast

func (l List[T]) DropLast(n int) List[T]

DropLast mirrors Seq.DropLast eagerly.

func (List[T]) DropWhile

func (l List[T]) DropWhile(pred func(T) bool) List[T]

DropWhile mirrors Seq.DropWhile eagerly.

func (List[T]) ElementAt

func (l List[T]) ElementAt(i int) (T, bool)

ElementAt mirrors Seq.ElementAt eagerly. O(1)/exact-allocation override.

func (List[T]) Filter

func (l List[T]) Filter(pred func(T) bool) List[T]

Filter mirrors Seq.Filter eagerly.

func (List[T]) FilterErr

func (l List[T]) FilterErr(pred func(T) (bool, error)) Try[T]

FilterErr mirrors Seq.FilterErr eagerly.

func (List[T]) FilterIndexed

func (l List[T]) FilterIndexed(pred func(int, T) bool) List[T]

FilterIndexed mirrors Seq.FilterIndexed eagerly.

func (List[T]) FilterMap

func (l List[T]) FilterMap[U any](f func(T) (U, bool)) List[U]

FilterMap mirrors Seq.FilterMap eagerly.

func (List[T]) FilterNot

func (l List[T]) FilterNot(pred func(T) bool) List[T]

FilterNot mirrors Seq.FilterNot eagerly.

func (List[T]) Find

func (l List[T]) Find(pred func(T) bool) (T, bool)

Find mirrors Seq.Find eagerly.

func (List[T]) FindIndex

func (l List[T]) FindIndex(pred func(T) bool) int

FindIndex mirrors Seq.FindIndex eagerly.

func (List[T]) FindLast

func (l List[T]) FindLast(pred func(T) bool) (T, bool)

FindLast mirrors Seq.FindLast eagerly.

func (List[T]) FindMap

func (l List[T]) FindMap[U any](f func(T) (U, bool)) (U, bool)

FindMap mirrors Seq.FindMap eagerly.

func (List[T]) First

func (l List[T]) First() (T, bool)

First mirrors Seq.First eagerly. O(1)/exact-allocation override.

func (List[T]) FlatMap

func (l List[T]) FlatMap[U any](f func(T) Seq[U]) List[U]

FlatMap mirrors Seq.FlatMap eagerly.

func (List[T]) FlatMapSlice

func (l List[T]) FlatMapSlice[U any](f func(T) []U) List[U]

FlatMapSlice mirrors Seq.FlatMapSlice eagerly.

func (List[T]) Fold

func (l List[T]) Fold[A any](init A, f func(A, T) A) A

Fold mirrors Seq.Fold eagerly.

func (List[T]) FoldBy

func (l List[T]) FoldBy[K comparable, A any](key func(T) K, init func(K) A, f func(A, T) A) map[K]A

FoldBy mirrors Seq.FoldBy eagerly.

func (List[T]) FoldErr

func (l List[T]) FoldErr[A any](init A, f func(A, T) (A, error)) (A, error)

FoldErr mirrors Seq.FoldErr eagerly.

func (List[T]) FoldIndexed

func (l List[T]) FoldIndexed[A any](init A, f func(int, A, T) A) A

FoldIndexed mirrors Seq.FoldIndexed eagerly.

func (List[T]) FoldRight

func (l List[T]) FoldRight[A any](init A, f func(T, A) A) A

FoldRight reduces right to left. It exists only on List: a right fold needs the whole sequence in memory, which a List already is (§7.5).

func (List[T]) FoldWhile

func (l List[T]) FoldWhile[A any](init A, f func(A, T) (A, bool)) A

FoldWhile mirrors Seq.FoldWhile eagerly.

func (List[T]) ForEach

func (l List[T]) ForEach(f func(T))

ForEach mirrors Seq.ForEach eagerly.

func (List[T]) ForEachErr

func (l List[T]) ForEachErr(f func(T) error) error

ForEachErr mirrors Seq.ForEachErr eagerly.

func (List[T]) ForEachIndexed

func (l List[T]) ForEachIndexed(f func(int, T))

ForEachIndexed mirrors Seq.ForEachIndexed eagerly.

func (List[T]) Get

func (l List[T]) Get(i int) (T, bool)

Get returns the element at index i; (zero, false) for a negative or out-of-range index. O(1).

func (List[T]) GroupBy

func (l List[T]) GroupBy[K comparable](sel func(T) K) map[K][]T

GroupBy mirrors Seq.GroupBy eagerly.

func (List[T]) IfEmpty

func (l List[T]) IfEmpty(defaults ...T) List[T]

IfEmpty mirrors Seq.IfEmpty eagerly.

func (List[T]) IndexBy

func (l List[T]) IndexBy[K comparable](sel func(T) K) map[K]T

IndexBy mirrors Seq.IndexBy eagerly.

func (List[T]) Intersperse

func (l List[T]) Intersperse(sep T) List[T]

Intersperse mirrors Seq.Intersperse eagerly.

func (List[T]) IsEmpty

func (l List[T]) IsEmpty() bool

IsEmpty mirrors Seq.IsEmpty eagerly. O(1)/exact-allocation override.

func (List[T]) JoinBy

func (l List[T]) JoinBy[U any, K comparable, R any](other Seq[U], leftKey func(T) K, rightKey func(U) K, combine func(T, U) R) List[R]

JoinBy mirrors Seq.JoinBy eagerly.

func (List[T]) JoinToString

func (l List[T]) JoinToString(sep string, sel func(T) string) string

JoinToString mirrors Seq.JoinToString eagerly.

func (List[T]) Last

func (l List[T]) Last() (T, bool)

Last mirrors Seq.Last eagerly. O(1)/exact-allocation override.

func (List[T]) Len

func (l List[T]) Len() int

Len returns the number of elements. O(1).

func (List[T]) Map

func (l List[T]) Map[U any](f func(T) U) List[U]

Map mirrors Seq.Map eagerly. O(1)/exact-allocation override.

func (List[T]) MapErr

func (l List[T]) MapErr[U any](f func(T) (U, error)) Try[U]

MapErr mirrors Seq.MapErr eagerly.

func (List[T]) MapIndexed

func (l List[T]) MapIndexed[U any](f func(int, T) U) List[U]

MapIndexed mirrors Seq.MapIndexed eagerly. O(1)/exact-allocation override.

func (List[T]) MaxBy

func (l List[T]) MaxBy[K cmp.Ordered](sel func(T) K) (T, bool)

MaxBy mirrors Seq.MaxBy eagerly.

func (List[T]) MaxOf

func (l List[T]) MaxOf[K cmp.Ordered](sel func(T) K) (K, bool)

MaxOf mirrors Seq.MaxOf eagerly.

func (List[T]) MaxWith

func (l List[T]) MaxWith(cmp func(a, b T) int) (T, bool)

MaxWith mirrors Seq.MaxWith eagerly.

func (List[T]) MinBy

func (l List[T]) MinBy[K cmp.Ordered](sel func(T) K) (T, bool)

MinBy mirrors Seq.MinBy eagerly.

func (List[T]) MinMaxOf

func (l List[T]) MinMaxOf[K cmp.Ordered](sel func(T) K) (min, max K, ok bool)

MinMaxOf mirrors Seq.MinMaxOf eagerly.

func (List[T]) MinOf

func (l List[T]) MinOf[K cmp.Ordered](sel func(T) K) (K, bool)

MinOf mirrors Seq.MinOf eagerly.

func (List[T]) MinWith

func (l List[T]) MinWith(cmp func(a, b T) int) (T, bool)

MinWith mirrors Seq.MinWith eagerly.

func (List[T]) None

func (l List[T]) None(pred func(T) bool) bool

None mirrors Seq.None eagerly.

func (List[T]) OnEach

func (l List[T]) OnEach(f func(T)) List[T]

OnEach mirrors Seq.OnEach eagerly.

func (List[T]) Partition

func (l List[T]) Partition(pred func(T) bool) (yes, no []T)

Partition mirrors Seq.Partition eagerly.

func (List[T]) Prepend

func (l List[T]) Prepend(vals ...T) List[T]

Prepend mirrors Seq.Prepend eagerly.

func (List[T]) ProductOf

func (l List[T]) ProductOf[N Numeric](sel func(T) N) N

ProductOf mirrors Seq.ProductOf eagerly.

func (List[T]) Reduce

func (l List[T]) Reduce(f func(T, T) T) (T, bool)

Reduce mirrors Seq.Reduce eagerly.

func (List[T]) Reversed

func (l List[T]) Reversed() List[T]

Reversed mirrors Seq.Reversed eagerly. O(1)/exact-allocation override.

func (List[T]) Scan

func (l List[T]) Scan[A any](init A, f func(A, T) A) List[A]

Scan mirrors Seq.Scan eagerly.

func (List[T]) Single

func (l List[T]) Single() (T, bool)

Single mirrors Seq.Single eagerly.

func (List[T]) Slice

func (l List[T]) Slice(i, j int) List[T]

Slice returns l[i:j] as a List, panicking exactly like the slice expression — and, exactly like it, sharing the backing array.

func (List[T]) SortedBy

func (l List[T]) SortedBy[K cmp.Ordered](sel func(T) K) List[T]

SortedBy mirrors Seq.SortedBy eagerly.

func (List[T]) SortedByDesc

func (l List[T]) SortedByDesc[K cmp.Ordered](sel func(T) K) List[T]

SortedByDesc mirrors Seq.SortedByDesc eagerly.

func (List[T]) SortedWith

func (l List[T]) SortedWith(cmp func(a, b T) int) List[T]

SortedWith mirrors Seq.SortedWith eagerly.

func (List[T]) Step

func (l List[T]) Step(n int) List[T]

Step mirrors Seq.Step eagerly.

func (List[T]) SumOf

func (l List[T]) SumOf[N Numeric](sel func(T) N) N

SumOf mirrors Seq.SumOf eagerly.

func (List[T]) Take

func (l List[T]) Take(n int) List[T]

Take mirrors Seq.Take eagerly.

func (List[T]) TakeLast

func (l List[T]) TakeLast(n int) List[T]

TakeLast mirrors Seq.TakeLast eagerly.

func (List[T]) TakeWhile

func (l List[T]) TakeWhile(pred func(T) bool) List[T]

TakeWhile mirrors Seq.TakeWhile eagerly.

func (List[T]) TallyBy

func (l List[T]) TallyBy[K comparable](sel func(T) K) map[K]int

TallyBy mirrors Seq.TallyBy eagerly.

func (List[T]) ToList

func (l List[T]) ToList() List[T]

ToList mirrors Seq.ToList eagerly. O(1)/exact-allocation override.

func (List[T]) TopNBy

func (l List[T]) TopNBy[K cmp.Ordered](n int, sel func(T) K) []T

TopNBy mirrors Seq.TopNBy eagerly.

func (List[T]) WithIndex

func (l List[T]) WithIndex() Seq2[int, T]

WithIndex mirrors Seq.WithIndex eagerly.

func (List[T]) ZipWithNext

func (l List[T]) ZipWithNext() Seq2[T, T]

ZipWithNext mirrors Seq.ZipWithNext eagerly.

type Numeric

type Numeric interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
		~float32 | ~float64
}

Numeric is the constraint for arithmetic aggregations (Sum, Product, Average). Complex types are deliberately excluded: they are unordered and half the aggregation surface would be meaningless for them.

type Seq

type Seq[T any] iter.Seq[T]

Seq is a lazy sequence: iter.Seq with methods. Range over it directly.

func Chain

func Chain[T any](seqs ...Seq[T]) Seq[T]

Chain yields each sequence's elements in order.

func Chunked

func Chunked[T any](s Seq[T], n int) Seq[[]T]

Chunked yields consecutive chunks of n elements; the last chunk may be partial. Every chunk is a fresh slice (safe to retain). Panics if n <= 0.

Chunked is a package function, not a method: a method on Seq[T] returning Seq[[]T] is an instantiation cycle (each Seq[T] would require Seq[[]T], which would require Seq[[][]T], forever).

func ChunkedBy

func ChunkedBy[T any, K comparable](s Seq[T], sel func(T) K) Seq[[]T]

ChunkedBy yields runs of consecutive elements sharing a key: a chunk closes when the key changes. Memory is bounded by the longest run. Every chunk is a fresh slice. A package function for the same instantiation- cycle reason as Chunked.

func Cycle

func Cycle[T any](s Seq[T]) Seq[T]

Cycle yields s over and over, forever. The first pass is buffered and replayed (⚠ unbounded memory in len(s)). An empty s yields an empty Cycle — it terminates rather than spinning.

func Dedupe

func Dedupe[T comparable](s Seq[T]) Seq[T]

Dedupe yields elements that differ from their predecessor — consecutive duplicates only, O(1) memory.

func Distinct

func Distinct[T comparable](s Seq[T]) Seq[T]

Distinct yields elements not seen before; the first occurrence wins. ⚠ Retains one entry per distinct value — unbounded.

func Empty

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

Empty returns the empty Seq.

func Except

func Except[T comparable](a, b Seq[T]) Seq[T]

Except yields the distinct elements of a that do not occur in b, in a's encounter order. ⚠ Buffers all of b before a is consumed, plus a seen- set of a's distinct values.

func Flatten

func Flatten[T any](s Seq[Seq[T]]) Seq[T]

Flatten yields every element of every inner sequence, in order.

func FlattenSlices

func FlattenSlices[T any](s Seq[[]T]) Seq[T]

FlattenSlices yields every element of every slice, in order.

func From

func From[T any](seq func(func(T) bool)) Seq[T]

From adapts any push-function sequence — iter.Seq, catena.Seq, or a third-party alias — with no conversion at the call site. Re-iterability depends on the source.

func FromChan

func FromChan[T any](ctx context.Context, ch <-chan T) Seq[T]

FromChan yields values received from ch until ch is closed or ctx is done. Single-use. No goroutine is started; a sequence that is never consumed never receives.

func FromSlice

func FromSlice[T any](s []T) Seq[T]

FromSlice returns a re-iterable Seq over s. The slice is not copied; mutations to it are visible to later iterations.

func Generate

func Generate[T any](seed T, next func(T) T) Seq[T]

Generate yields seed, then next(seed), then next(next(seed)), forever. Infinite. Re-iterable iff next is pure.

func GenerateWhile

func GenerateWhile[T any](seed T, next func(T) (T, bool)) Seq[T]

GenerateWhile yields seed unconditionally, then successive next values until next reports false.

func Intersect

func Intersect[T comparable](a, b Seq[T]) Seq[T]

Intersect yields the distinct elements of a that occur in b, in a's encounter order. ⚠ Buffers all of b before a is consumed, plus a seen- set of a's distinct values.

func NonZero

func NonZero[T comparable](s Seq[T]) Seq[T]

NonZero yields the elements that are not the zero value of T.

func Of

func Of[T any](vals ...T) Seq[T]

Of returns a re-iterable Seq over the given values.

func Once1

func Once1[T any](v T) Seq[T]

Once1 returns a re-iterable Seq of exactly one value. (Once, without the suffix, is the single-use guard method on Seq.)

func Range

func Range[I Integer](start, stop, step I) Seq[I]

Range yields start, start+step, ... while the value is before stop (exclusive). step == 0 panics at construction; a sign mismatch between step and the start→stop direction yields an empty sequence. Termination is overflow-guarded: a step past the type's edge stops rather than wrapping. Unsigned types cannot step downward.

Example
package main

import (
	"fmt"

	"github.com/NerdMeNot/catena"
)

func main() {
	evens := catena.Range(0, 10, 2).
		Map(func(n int) int { return n * n }).
		Collect()
	fmt.Println(evens)
}
Output:
[0 4 16 36 64]

func Repeat

func Repeat[T any](v T) Seq[T]

Repeat yields v forever. Infinite: pair with Take or a conditional terminal.

func RepeatN

func RepeatN[T any](v T, n int) Seq[T]

RepeatN yields v exactly n times. Panics if n is negative.

func Sorted

func Sorted[T cmp.Ordered](s Seq[T]) Seq[T]

Sorted yields the elements in ascending order, stably. NaN sorts first. ⚠ Buffers the entire input.

func SortedDesc

func SortedDesc[T cmp.Ordered](s Seq[T]) Seq[T]

SortedDesc yields the elements in descending order, stably. ⚠ Buffers the entire input.

func Union

func Union[T comparable](a, b Seq[T]) Seq[T]

Union yields the distinct elements of a, then the distinct elements of b not in a — set semantics, encounter order. ⚠ Retains one entry per distinct value — unbounded.

func Windowed

func Windowed[T any](s Seq[T], size, step int) Seq[[]T]

Windowed yields sliding windows of exactly size elements, advancing by step; trailing elements that do not fill a window are dropped. step > size is valid and samples with gaps. ⚠ Buffers size elements. Every window is a fresh slice. Panics if size or step is <= 0. A package function for the same instantiation-cycle reason as Chunked.

func (Seq[T]) All

func (s Seq[T]) All(pred func(T) bool) bool

All reports whether pred admits every element; stops at the first counterexample. Vacuously true on empty input.

func (Seq[T]) Any

func (s Seq[T]) Any(pred func(T) bool) bool

Any reports whether pred admits any element; stops at the first match.

func (Seq[T]) Append

func (s Seq[T]) Append(vals ...T) Seq[T]

Append yields s, then the given values.

func (Seq[T]) Associate

func (s Seq[T]) Associate[K comparable, V any](f func(T) (K, V)) map[K]V

Associate builds a map from f's key/value pairs; on duplicate keys the last pair wins. ⚠ Full drain; map iteration order is undefined.

func (Seq[T]) AverageOf

func (s Seq[T]) AverageOf[N Numeric](sel func(T) N) (float64, bool)

AverageOf returns the mean of the selected values, accumulating in float64 (naive summation — precision for large integer inputs is not guaranteed); (0, false) on empty input. ⚠ Full drain.

func (Seq[T]) BottomNBy

func (s Seq[T]) BottomNBy[K cmp.Ordered](n int, sel func(T) K) []T

BottomNBy returns the n elements with the smallest keys, sorted ascending by key; equal keys retain encounter order. Memory is O(n). ⚠ Full drain. Panics if n is negative.

func (Seq[T]) Collect

func (s Seq[T]) Collect() []T

Collect drains the sequence into a slice; nil for empty. ⚠ Full drain.

func (Seq[T]) Concat

func (s Seq[T]) Concat(others ...Seq[T]) Seq[T]

Concat yields s, then each of the others in order.

func (Seq[T]) Count

func (s Seq[T]) Count() int

Count returns the number of elements. ⚠ Full drain.

func (Seq[T]) CountWhere

func (s Seq[T]) CountWhere(pred func(T) bool) int

CountWhere returns the number of elements pred admits. ⚠ Full drain.

func (Seq[T]) DedupeBy

func (s Seq[T]) DedupeBy[K comparable](sel func(T) K) Seq[T]

DedupeBy yields elements whose key differs from the previous element's key — consecutive duplicates only, O(1) memory. On key-sorted input it equals DistinctBy at a fraction of the cost.

func (Seq[T]) DistinctBy

func (s Seq[T]) DistinctBy[K comparable](sel func(T) K) Seq[T]

DistinctBy yields elements whose key has not been seen before; the first occurrence wins. ⚠ Retains one key per distinct value — unbounded.

func (Seq[T]) DistinctWith

func (s Seq[T]) DistinctWith(eq func(a, b T) bool) Seq[T]

DistinctWith yields elements no earlier element equals under eq. First occurrence wins. ⚠ Retains all distinct elements and compares in O(n²) — small inputs only.

func (Seq[T]) Drain

func (s Seq[T]) Drain()

Drain consumes the sequence for its side effects. ⚠ Full drain.

func (Seq[T]) Drop

func (s Seq[T]) Drop(n int) Seq[T]

Drop skips the first n elements. Panics if n is negative.

func (Seq[T]) DropLast

func (s Seq[T]) DropLast(n int) Seq[T]

DropLast yields all but the final n elements, emitting with an n-element lag (⚠ buffers n). Panics if n is negative.

func (Seq[T]) DropWhile

func (s Seq[T]) DropWhile(pred func(T) bool) Seq[T]

DropWhile skips elements until pred first returns false, then yields the rest.

func (Seq[T]) ElementAt

func (s Seq[T]) ElementAt(i int) (T, bool)

ElementAt returns the element at index i; (zero, false) for a negative or out-of-range index.

func (Seq[T]) Filter

func (s Seq[T]) Filter(pred func(T) bool) Seq[T]

Filter yields the elements for which pred returns true.

func (Seq[T]) FilterErr

func (s Seq[T]) FilterErr(pred func(T) (bool, error)) Try[T]

FilterErr yields elements pred admits, as a Try; a failed pred call yields (zero, err).

func (Seq[T]) FilterIndexed

func (s Seq[T]) FilterIndexed(pred func(int, T) bool) Seq[T]

FilterIndexed yields the elements for which pred(index, element) returns true. The index counts source elements from 0.

func (Seq[T]) FilterMap

func (s Seq[T]) FilterMap[U any](f func(T) (U, bool)) Seq[U]

FilterMap yields the mapped value for each element f reports true for — a fused Map + Filter.

func (Seq[T]) FilterNot

func (s Seq[T]) FilterNot(pred func(T) bool) Seq[T]

FilterNot yields the elements for which pred returns false.

func (Seq[T]) Find

func (s Seq[T]) Find(pred func(T) bool) (T, bool)

Find returns the first element pred admits.

func (Seq[T]) FindIndex

func (s Seq[T]) FindIndex(pred func(T) bool) int

FindIndex returns the index of the first element pred admits; -1 if none.

func (Seq[T]) FindLast

func (s Seq[T]) FindLast(pred func(T) bool) (T, bool)

FindLast returns the final element pred admits. ⚠ Full drain.

func (Seq[T]) FindMap

func (s Seq[T]) FindMap[U any](f func(T) (U, bool)) (U, bool)

FindMap returns the first mapped value f reports true for — a fused Find + Map.

func (Seq[T]) First

func (s Seq[T]) First() (T, bool)

First returns the first element.

func (Seq[T]) FlatMap

func (s Seq[T]) FlatMap[U any](f func(T) Seq[U]) Seq[U]

FlatMap yields all elements of f(v) for each element v, in order.

func (Seq[T]) FlatMapSlice

func (s Seq[T]) FlatMapSlice[U any](f func(T) []U) Seq[U]

FlatMapSlice yields all elements of the slice f(v) for each element v.

func (Seq[T]) Fold

func (s Seq[T]) Fold[A any](init A, f func(A, T) A) A

Fold reduces the sequence into an accumulator, left to right. ⚠ Full drain.

func (Seq[T]) FoldBy

func (s Seq[T]) FoldBy[K comparable, A any](
	key func(T) K, init func(K) A, f func(A, T) A,
) map[K]A

FoldBy folds each element into a per-key accumulator: streaming grouped aggregation with no intermediate per-key slices. init is called once per distinct key. Memory is bounded by the number of distinct keys, not elements. ⚠ Full drain; map iteration order is undefined.

Example
package main

import (
	"fmt"

	"github.com/NerdMeNot/catena"
)

func main() {
	type order struct {
		user   string
		amount int
	}
	orders := catena.Of(
		order{"ada", 30}, order{"bob", 10}, order{"ada", 25}, order{"bob", 5},
	)
	// Streaming per-key aggregation: no intermediate map[string][]order.
	totals := orders.FoldBy(
		func(o order) string { return o.user },
		func(string) int { return 0 },
		func(sum int, o order) int { return sum + o.amount },
	)
	fmt.Println(totals["ada"], totals["bob"])
}
Output:
55 15

func (Seq[T]) FoldErr

func (s Seq[T]) FoldErr[A any](init A, f func(A, T) (A, error)) (A, error)

FoldErr folds until f fails, returning the accumulator so far and the first error.

func (Seq[T]) FoldIndexed

func (s Seq[T]) FoldIndexed[A any](init A, f func(int, A, T) A) A

FoldIndexed is Fold with the element index. ⚠ Full drain.

func (Seq[T]) FoldWhile

func (s Seq[T]) FoldWhile[A any](init A, f func(A, T) (A, bool)) A

FoldWhile folds until f reports false; the accumulator from the stopping call is included in the result.

func (Seq[T]) ForEach

func (s Seq[T]) ForEach(f func(T))

ForEach calls f on every element. ⚠ Full drain.

func (Seq[T]) ForEachErr

func (s Seq[T]) ForEachErr(f func(T) error) error

ForEachErr calls f on every element, stopping at and returning the first non-nil error; nil if the sequence drains clean.

func (Seq[T]) ForEachIndexed

func (s Seq[T]) ForEachIndexed(f func(int, T))

ForEachIndexed calls f(index, element) on every element. ⚠ Full drain.

func (Seq[T]) GroupBy

func (s Seq[T]) GroupBy[K comparable](sel func(T) K) map[K][]T

GroupBy collects elements into per-key buckets, each in encounter order. ⚠ Full drain; retains every element; map iteration order is undefined.

func (Seq[T]) IfEmpty

func (s Seq[T]) IfEmpty(defaults ...T) Seq[T]

IfEmpty yields s, or the given defaults if s yields nothing.

func (Seq[T]) IndexBy

func (s Seq[T]) IndexBy[K comparable](sel func(T) K) map[K]T

IndexBy maps each key to its element; on duplicate keys the last element wins. ⚠ Full drain; map iteration order is undefined.

func (Seq[T]) Intersperse

func (s Seq[T]) Intersperse(sep T) Seq[T]

Intersperse yields sep between consecutive elements.

func (Seq[T]) IsEmpty

func (s Seq[T]) IsEmpty() bool

IsEmpty reports whether the sequence yields nothing. ⚠ It does so by consuming one element — on a single-pass source that element is lost.

func (Seq[T]) JoinBy

func (s Seq[T]) JoinBy[U any, K comparable, R any](
	other Seq[U],
	leftKey func(T) K, rightKey func(U) K,
	combine func(T, U) R,
) Seq[R]

JoinBy is a relational inner join: it pairs each element of s with every element of other sharing the same key and yields combine for each pair. Unmatched elements on either side are dropped; duplicate keys produce the cross product per key. Output order is left encounter order, then right encounter order within a key. ⚠ Buffers all of other before the first emission.

func (Seq[T]) JoinToString

func (s Seq[T]) JoinToString(sep string, sel func(T) string) string

JoinToString concatenates the selected strings with sep between elements. ⚠ Full drain.

func (Seq[T]) Last

func (s Seq[T]) Last() (T, bool)

Last returns the final element. ⚠ Full drain.

func (Seq[T]) Map

func (s Seq[T]) Map[U any](f func(T) U) Seq[U]

Map yields f applied to each element.

func (Seq[T]) MapErr

func (s Seq[T]) MapErr[U any](f func(T) (U, error)) Try[U]

MapErr yields f applied to each element as a Try; a failed call yields (zero, err).

func (Seq[T]) MapIndexed

func (s Seq[T]) MapIndexed[U any](f func(int, T) U) Seq[U]

MapIndexed yields f(index, element), counting from 0.

func (Seq[T]) MaxBy

func (s Seq[T]) MaxBy[K cmp.Ordered](sel func(T) K) (T, bool)

MaxBy returns the element with the largest key; the earliest maximal element wins ties. NaN keys order below everything (cmp.Compare). ⚠ Full drain.

func (Seq[T]) MaxOf

func (s Seq[T]) MaxOf[K cmp.Ordered](sel func(T) K) (K, bool)

MaxOf returns the largest key. ⚠ Full drain.

func (Seq[T]) MaxWith

func (s Seq[T]) MaxWith(cmp func(a, b T) int) (T, bool)

MaxWith returns the largest element under cmp; the earliest maximal element wins ties. ⚠ Full drain.

func (Seq[T]) MinBy

func (s Seq[T]) MinBy[K cmp.Ordered](sel func(T) K) (T, bool)

MinBy returns the element with the smallest key; the earliest minimal element wins ties. ⚠ Full drain.

func (Seq[T]) MinMaxOf

func (s Seq[T]) MinMaxOf[K cmp.Ordered](sel func(T) K) (min, max K, ok bool)

MinMaxOf returns the smallest and largest keys in one pass. ⚠ Full drain.

func (Seq[T]) MinOf

func (s Seq[T]) MinOf[K cmp.Ordered](sel func(T) K) (K, bool)

MinOf returns the smallest key. ⚠ Full drain.

func (Seq[T]) MinWith

func (s Seq[T]) MinWith(cmp func(a, b T) int) (T, bool)

MinWith returns the smallest element under cmp; the earliest minimal element wins ties. ⚠ Full drain.

func (Seq[T]) None

func (s Seq[T]) None(pred func(T) bool) bool

None reports whether pred admits no element; stops at the first match.

func (Seq[T]) OnEach

func (s Seq[T]) OnEach(f func(T)) Seq[T]

OnEach calls f on every element and passes it through unchanged.

func (Seq[T]) Once

func (s Seq[T]) Once() Seq[T]

Once returns a sequence that panics if iterated more than once — a development guard for the single-pass contract, not a synchronization mechanism. This is the one operator whose state deliberately lives outside the iteration closure.

func (Seq[T]) Partition

func (s Seq[T]) Partition(pred func(T) bool) (yes, no []T)

Partition splits elements by pred, preserving encounter order on both sides; nil slices for empty sides. ⚠ Full drain.

func (Seq[T]) Prepend

func (s Seq[T]) Prepend(vals ...T) Seq[T]

Prepend yields the given values, then s.

func (Seq[T]) ProductOf

func (s Seq[T]) ProductOf[N Numeric](sel func(T) N) N

ProductOf multiplies the selected values. Empty input yields 1, the multiplicative identity. ⚠ Full drain.

func (Seq[T]) Pull

func (s Seq[T]) Pull() (next func() (T, bool), stop func())

Pull converts s to a pull-based iterator. THE CALLER MUST CALL stop, even if next has returned false, or resources held by s will leak.

func (Seq[T]) Reduce

func (s Seq[T]) Reduce(f func(T, T) T) (T, bool)

Reduce folds the sequence using its first element as the initial accumulator; (zero, false) on empty input. ⚠ Full drain.

func (Seq[T]) Reversed

func (s Seq[T]) Reversed() Seq[T]

Reversed yields the elements in reverse order. ⚠ Buffers the entire input — hangs on infinite input.

func (Seq[T]) Scan

func (s Seq[T]) Scan[A any](init A, f func(A, T) A) Seq[A]

Scan yields the running accumulator: f(init, e0), f(that, e1), ... The initial value itself is not yielded.

func (Seq[T]) Seq

func (s Seq[T]) Seq() iter.Seq[T]

Seq converts to the stdlib iterator type. Free.

func (Seq[T]) Single

func (s Seq[T]) Single() (T, bool)

Single returns the element iff the sequence has exactly one; it stops consuming upon seeing a second.

func (Seq[T]) SortedBy

func (s Seq[T]) SortedBy[K cmp.Ordered](sel func(T) K) Seq[T]

SortedBy yields the elements sorted ascending by key, stably. sel is called exactly once per element (decorate-sort-undecorate). ⚠ Buffers the entire input — hangs on infinite input.

func (Seq[T]) SortedByDesc

func (s Seq[T]) SortedByDesc[K cmp.Ordered](sel func(T) K) Seq[T]

SortedByDesc yields the elements sorted descending by key, stably. sel is called exactly once per element. ⚠ Buffers the entire input — hangs on infinite input.

func (Seq[T]) SortedWith

func (s Seq[T]) SortedWith(cmp func(a, b T) int) Seq[T]

SortedWith yields the elements sorted by cmp, stably. ⚠ Buffers the entire input — hangs on infinite input.

func (Seq[T]) Step

func (s Seq[T]) Step(n int) Seq[T]

Step yields the first element and every nth element after it. Panics if n <= 0.

func (Seq[T]) SumOf

func (s Seq[T]) SumOf[N Numeric](sel func(T) N) N

SumOf sums the selected values; integer overflow wraps like +. Empty input sums to 0. ⚠ Full drain.

func (Seq[T]) Take

func (s Seq[T]) Take(n int) Seq[T]

Take yields at most the first n elements, consuming exactly as many as it yields. Panics if n is negative.

func (Seq[T]) TakeLast

func (s Seq[T]) TakeLast(n int) Seq[T]

TakeLast yields the final n elements. ⚠ Buffers n elements and fully drains the source before emitting — hangs on infinite input. Panics if n is negative.

func (Seq[T]) TakeWhile

func (s Seq[T]) TakeWhile(pred func(T) bool) Seq[T]

TakeWhile yields elements until pred first returns false.

func (Seq[T]) TallyBy

func (s Seq[T]) TallyBy[K comparable](sel func(T) K) map[K]int

TallyBy counts elements per key. ⚠ Full drain; map iteration order is undefined.

func (Seq[T]) ToChan

func (s Seq[T]) ToChan(ctx context.Context) <-chan T

ToChan starts a goroutine that sends every element on the returned unbuffered channel. The channel is closed when the sequence ends or ctx is done — the consumer must drain or cancel, or the goroutine leaks.

func (Seq[T]) ToList

func (s Seq[T]) ToList() List[T]

ToList drains the sequence into a List; nil for empty. ⚠ Full drain.

func (Seq[T]) TopNBy

func (s Seq[T]) TopNBy[K cmp.Ordered](n int, sel func(T) K) []T

TopNBy returns the n elements with the largest keys, sorted descending by key; equal keys retain encounter order and the earliest elements win at the cut. Memory is O(n) — the streaming alternative to SortedByDesc().Take(n). ⚠ Full drain. Panics if n is negative.

Example
package main

import (
	"fmt"

	"github.com/NerdMeNot/catena"
)

func main() {
	words := catena.Of("chain", "of", "sequences", "linked", "as", "one")
	// Bounded-heap selection: O(3) memory, not a full sort.
	fmt.Println(words.TopNBy(3, func(w string) int { return len(w) }))
}
Output:
[sequences linked chain]

func (Seq[T]) UntilDone

func (s Seq[T]) UntilDone(ctx context.Context) Try[T]

UntilDone passes elements through until ctx is done, then yields (zero, ctx.Err()) and stops.

func (Seq[T]) WithIndex

func (s Seq[T]) WithIndex() Seq2[int, T]

WithIndex pairs each element with its index, counting from 0.

func (Seq[T]) Zip

func (s Seq[T]) Zip[U any](other Seq[U]) Seq2[T, U]

Zip pairs elements of s with elements of other, stopping at the shorter side. The receiver drives; other is consumed through iter.Pull (its cleanup always runs). other is pulled once per emitted pair; the receiver is consumed one element past the pair count when other is shorter.

func (Seq[T]) ZipWithNext

func (s Seq[T]) ZipWithNext() Seq2[T, T]

ZipWithNext yields each adjacent pair (element, next element). Empty and single-element input yield nothing.

type Seq2

type Seq2[K, V any] iter.Seq2[K, V]

Seq2 is a lazy pair sequence: iter.Seq2 with methods. It is a bridge back to Seq (via Keys, Values, MapTo), deliberately not a full peer surface.

func Empty2

func Empty2[K, V any]() Seq2[K, V]

Empty2 returns the empty Seq2.

func From2

func From2[K, V any](seq func(func(K, V) bool)) Seq2[K, V]

From2 adapts any push-function pair sequence.

func FromMap

func FromMap[K comparable, V any](m map[K]V) Seq2[K, V]

FromMap returns a re-iterable Seq2 over m, in undefined (map) order.

func (Seq2[K, V]) All

func (s Seq2[K, V]) All(pred func(K, V) bool) bool

All reports whether pred admits every pair; stops at the first counterexample. Vacuously true on empty input.

func (Seq2[K, V]) Any

func (s Seq2[K, V]) Any(pred func(K, V) bool) bool

Any reports whether pred admits any pair; stops at the first match.

func (Seq2[K, V]) Count

func (s Seq2[K, V]) Count() int

Count returns the number of pairs. ⚠ Full drain.

func (Seq2[K, V]) Drop

func (s Seq2[K, V]) Drop(n int) Seq2[K, V]

Drop skips the first n pairs. Panics if n is negative.

func (Seq2[K, V]) Filter

func (s Seq2[K, V]) Filter(pred func(K, V) bool) Seq2[K, V]

Filter yields the pairs pred admits.

func (Seq2[K, V]) FilterNot

func (s Seq2[K, V]) FilterNot(pred func(K, V) bool) Seq2[K, V]

FilterNot yields the pairs pred rejects.

func (Seq2[K, V]) First

func (s Seq2[K, V]) First() (K, V, bool)

First returns the first pair.

func (Seq2[K, V]) Fold

func (s Seq2[K, V]) Fold[A any](init A, f func(A, K, V) A) A

Fold reduces the pairs into an accumulator, left to right. ⚠ Full drain.

func (Seq2[K, V]) ForEach

func (s Seq2[K, V]) ForEach(f func(K, V))

ForEach calls f on every pair. ⚠ Full drain.

func (Seq2[K, V]) Keys

func (s Seq2[K, V]) Keys() Seq[K]

Keys yields the first element of each pair. Calling Keys and Values on the same single-pass Seq2 is a double consume — use Unzip.

func (Seq2[K, V]) Map

func (s Seq2[K, V]) Map[K2, V2 any](f func(K, V) (K2, V2)) Seq2[K2, V2]

Map yields f applied to each pair.

func (Seq2[K, V]) MapTo

func (s Seq2[K, V]) MapTo[U any](f func(K, V) U) Seq[U]

MapTo collapses each pair into one value — the intended exit back to Seq and its full API.

func (Seq2[K, V]) MapValues

func (s Seq2[K, V]) MapValues[V2 any](f func(K, V) V2) Seq2[K, V2]

MapValues yields each pair with its value replaced by f(k, v). f receives the key too (Kotlin-consistent).

func (Seq2[K, V]) Pull

func (s Seq2[K, V]) Pull() (next func() (K, V, bool), stop func())

Pull converts s to a pull-based iterator. THE CALLER MUST CALL stop, even if next has returned false, or resources held by s will leak.

func (Seq2[K, V]) Seq2

func (s Seq2[K, V]) Seq2() iter.Seq2[K, V]

Seq2 converts to the stdlib iterator type. Free.

func (Seq2[K, V]) Swap

func (s Seq2[K, V]) Swap() Seq2[V, K]

Swap yields each pair with its sides exchanged.

func (Seq2[K, V]) Take

func (s Seq2[K, V]) Take(n int) Seq2[K, V]

Take yields at most the first n pairs. Panics if n is negative.

func (Seq2[K, V]) Values

func (s Seq2[K, V]) Values() Seq[V]

Values yields the second element of each pair.

type Try

type Try[T any] iter.Seq2[T, error]

Try is a lazy sequence of fallible elements: iter.Seq2[T, error] with methods. When err != nil the value must not be read.

func EmptyTry

func EmptyTry[T any]() Try[T]

EmptyTry returns the empty Try.

func FromErrs

func FromErrs[T any](seq func(func(T, error) bool)) Try[T]

FromErrs adapts any push-function fallible sequence.

func (Try[T]) Collect

func (t Try[T]) Collect() ([]T, error)

Collect gathers successful elements until the first error, returning the partial slice and that error (R5); (all elements, nil) on a clean drain. Nil slice for empty.

Example
package main

import (
	"fmt"

	"github.com/NerdMeNot/catena"
)

func main() {
	nums := catena.Of("1", "2", "x", "4").MapErr(func(s string) (int, error) {
		var n int
		_, err := fmt.Sscanf(s, "%d", &n)
		return n, err
	})
	// The consumer picks the error policy: stop at the first error...
	vals, err := nums.Collect()
	fmt.Println(vals, err != nil)
	// ...or skip failures and keep going.
	fmt.Println(nums.Ignore().Collect())
}
Output:
[1 2] true
[1 2 4]

func (Try[T]) CollectAll

func (t Try[T]) CollectAll() ([]T, []error)

CollectAll drains everything, gathering all successes and all errors. Positional correspondence between the two slices is lost. Nil slices when empty. ⚠ Full drain.

func (Try[T]) Count

func (t Try[T]) Count() (int, error)

Count counts successful elements up to the first error, which is returned alongside the count so far (R5).

func (Try[T]) Drop

func (t Try[T]) Drop(n int) Try[T]

Drop skips the first n elements, errored or not (R2). Panics if n is negative.

func (Try[T]) Err

func (t Try[T]) Err() error

Err consumes until the first error and returns it; nil on a clean drain (R5).

func (Try[T]) Errs

func (t Try[T]) Errs() Seq[error]

Errs yields the errors, dropping successful elements — the dual of Ignore. Ignore and Errs on the same single-pass Try is a double consume; use CollectAll.

func (Try[T]) Filter

func (t Try[T]) Filter(pred func(T) bool) Try[T]

Filter yields the successful elements pred admits; errored elements pass through unexamined.

func (Try[T]) FilterErr

func (t Try[T]) FilterErr(pred func(T) (bool, error)) Try[T]

FilterErr yields the successful elements pred admits; a failed pred call yields (zero, err); errored elements pass through unexamined.

func (Try[T]) FlatMap

func (t Try[T]) FlatMap[U any](f func(T) Try[U]) Try[U]

FlatMap yields every element of f(v) for each successful element v, in order; an errored input element passes through un-mapped.

func (Try[T]) Fold

func (t Try[T]) Fold[A any](init A, f func(A, T) A) (A, error)

Fold reduces successful elements until the first error, returning the accumulator so far and that error (R5).

func (Try[T]) ForEach

func (t Try[T]) ForEach(f func(T) error) error

ForEach calls f on each successful element, stopping at and returning the first of an element error or a non-nil f return (R5).

func (Try[T]) Ignore

func (t Try[T]) Ignore() Seq[T]

Ignore yields the successful elements, dropping errored ones.

func (Try[T]) Map

func (t Try[T]) Map[U any](f func(T) U) Try[U]

Map yields f applied to each successful element; errored elements pass through.

func (Try[T]) MapErr

func (t Try[T]) MapErr[U any](f func(T) (U, error)) Try[U]

MapErr yields f applied to each successful element; a failed call yields (zero, err); errored elements pass through.

func (Try[T]) Must

func (t Try[T]) Must() Seq[T]

Must yields the successful elements and panics with the error value on the first error — recover() receives the error itself.

func (Try[T]) OnEach

func (t Try[T]) OnEach(f func(T)) Try[T]

OnEach calls f on every successful element and passes everything through.

func (Try[T]) OnError

func (t Try[T]) OnError(f func(error)) Try[T]

OnError calls f on every error and passes everything through — a logging hook.

func (Try[T]) Pull

func (t Try[T]) Pull() (next func() (T, error, bool), stop func())

Pull converts t to a pull-based iterator. THE CALLER MUST CALL stop, even if next has returned false, or resources held by t will leak.

func (Try[T]) Recover

func (t Try[T]) Recover(f func(error) (T, bool)) Try[T]

Recover offers each error to f: reporting true replaces the element with (v, nil); reporting false passes the error through unchanged.

func (Try[T]) Seq2

func (t Try[T]) Seq2() iter.Seq2[T, error]

Seq2 converts to the stdlib iterator type. Free.

func (Try[T]) Take

func (t Try[T]) Take(n int) Try[T]

Take yields at most the first n elements, errored or not (R2). Panics if n is negative.

func (Try[T]) TakeWhile

func (t Try[T]) TakeWhile(pred func(T) bool) Try[T]

TakeWhile yields elements until pred rejects a successful element; errored elements pass through and do not terminate (R3).

func (Try[T]) UntilDone

func (t Try[T]) UntilDone(ctx context.Context) Try[T]

UntilDone passes elements through until ctx is done, then yields (zero, ctx.Err()) and stops.

func (Try[T]) WrapErr

func (t Try[T]) WrapErr(f func(error) error) Try[T]

WrapErr replaces each error with f(err) — the place to add positional context. If f returns nil (a caller bug), the original error is kept: an error is never converted into a zero-value success.

Directories

Path Synopsis
examples
01-basics command
Basics: building a pipeline, what laziness means in practice, and how catena sequences interoperate with plain range loops and iter.Seq.
Basics: building a pipeline, what laziness means in practice, and how catena sequences interoperate with plain range loops and iter.Seq.
02-grouping command
Grouping: FoldBy is the library's centerpiece — streaming aggregation bounded by distinct keys, not elements.
Grouping: FoldBy is the library's centerpiece — streaming aggregation bounded by distinct keys, not elements.
03-selection command
Selection: finding extremes and top-k without sorting the world.
Selection: finding extremes and top-k without sorting the world.
04-errors command
Errors: one parse pipeline, three policies.
Errors: one parse pipeline, three policies.
05-resources command
Resources: a producer that owns something — here a real temp file — opens it lazily inside the iteration closure.
Resources: a producer that owns something — here a real temp file — opens it lazily inside the iteration closure.
06-streaming command
Streaming: sequences with no end, and the operators that stay safe on them — running state with Scan, moving averages with Windowed, batching with Chunked, and change detection with DedupeBy.
Streaming: sequences with no end, and the operators that stay safe on them — running state with Scan, moving averages with Windowed, batching with Chunked, and change detection with DedupeBy.
07-join command
Join: JoinBy is a relational inner join between two streams of structs — the right side is indexed by key, the left side streams past it, and the joined stream is a plain Seq you keep chaining on.
Join: JoinBy is a relational inner join between two streams of structs — the right side is indexed by key, the left side streams past it, and the joined stream is a plain Seq you keep chaining on.
08-list command
List and the Seq2 bridge: when the data is small and already in memory, eager evaluation with exact preallocation beats a lazy chain — and the two worlds convert explicitly, in both directions.
List and the Seq2 bridge: when the data is small and already in memory, eager evaluation with exact preallocation beats a lazy chain — and the two worlds convert explicitly, in both directions.
internal
gen/listgen command
Command listgen generates list_gen.go: the eager List[T] mirror of the Seq[T] operation set (§10 of the spec).
Command listgen generates list_gen.go: the eager List[T] mirror of the Seq[T] operation set (§10 of the spec).

Jump to

Keyboard shortcuts

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