xiter

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 8, 2026 License: MIT Imports: 3 Imported by: 0

README

xiter

Go Version CI Coverage Status Release Go Report Card Go Reference

Iterator utilities for iter.Seq and iter.Seq2. Wraps both sequence types with chainable methods so operations can be composed without intermediate allocations.

Stability

v1.x releases make no breaking changes to exported APIs. New functionality may be added in minor releases; patches are bug fixes, or administrative work only.

Release of v1.x will be delayed until after the release of go 1.27 in order to support chaining of the Transform functions.

Installation

Go 1.26.2 or later.

go get github.com/wood-jp/xiter

Usage

Wrapping sequences

Any iter.Seq[V] or iter.Seq2[K, V] can be wrapped for chaining with a type conversion or the ToSeq/ToSeq2 helpers:

// type conversion
s := xiter.Seq[int](slices.Values([]int{1, 2, 3, 4, 5}))

// helper (useful when the compiler can't infer the type parameter)
s := xiter.ToSeq(slices.Values([]int{1, 2, 3, 4, 5}))
s2 := xiter.ToSeq2(slices.All([]string{"a", "b", "c"}))

Call .Iter() on either wrapper to get back the underlying iter.Seq/iter.Seq2 for use with stdlib functions.

Filter

Filter yields only the elements for which the predicate returns true.

evens := xiter.Seq[int](slices.Values([]int{1, 2, 3, 4, 5})).
    Filter(func(v int) bool { return v%2 == 0 }).
    Collect()
// []int{2, 4}

Seq2.Filter receives both the key and value:

for k, v := range xiter.ToSeq2(slices.All(words)).Filter(func(i int, s string) bool {
    return i%2 == 0
}) {
    fmt.Println(k, v)
}
Transform

Transform maps each element of a Seq[V] through a function, yielding a Seq[T]. Because Go does not yet allow methods to introduce new type parameters, Transform is a package-level function rather than a method on Seq. This restriction is expected to be lifted in Go 1.27 (golang/go#77273).

strs := xiter.Transform(
    xiter.Seq[int](slices.Values([]int{1, 2, 3})),
    strconv.Itoa,
).Collect()
// []string{"1", "2", "3"}

Transform2 maps each (K1, V1) pair of a Seq2 through a function, yielding a Seq2[K2, V2]:

upper := xiter.Transform2(
    xiter.ToSeq2(slices.All([]string{"a", "b", "c"})),
    func(k int, v string) (int, string) { return k, strings.ToUpper(v) },
)

TransformToSeq2 converts a Seq[V] to a Seq2[K, V2] (e.g. pairing each element with a derived key). TransformToSeq does the reverse, collapsing each (K, V) pair into a single T.

// pair each word with its length as the key
withLen := xiter.TransformToSeq2(
    xiter.Seq[string](slices.Values([]string{"go", "rust", "zig"})),
    func(v string) (int, string) { return len(v), v },
)
// Seq2[int, string]: (2,"go"), (4,"rust"), (3,"zig")
Limit

Limit stops iteration after at most n elements.

first3 := xiter.Seq[int](slices.Values([]int{1, 2, 3, 4, 5})).
    Limit(3).
    Collect()
// []int{1, 2, 3}
Skip

Skip discards the first n elements then yields the rest.

after2 := xiter.Seq[int](slices.Values([]int{1, 2, 3, 4, 5})).
    Skip(2).
    Collect()
// []int{3, 4, 5}
Collect

Seq[V].Collect() materializes the sequence into a []V. Seq2[K, V].Collect() materializes the sequence into a map[K]V.

m := xiter.ToSeq2(slices.All([]string{"a", "b", "c"})).Collect()
// map[int]string{0: "a", 1: "b", 2: "c"}
BoolSeq

BoolSeq is a named wrapper around Seq[bool] that adds terminal operations And and Or, the non-terminal Not, and an Iter escape hatch.

Produce a BoolSeq from any Seq[V] or Seq2[K, V] via MapBool, which applies a predicate to each element:

// are all even numbers > 0?
ok := xiter.Seq[int](slices.Values([]int{2, 4, 6})).
    MapBool(func(v int) bool { return v > 0 }).
    And()
// true

// does any word start with "go"?
found := xiter.Seq[string](slices.Values([]string{"rust", "go", "zig"})).
    MapBool(func(v string) bool { return strings.HasPrefix(v, "go") }).
    Or()
// true

Seq2.MapBool receives both the key and value:

allEvenIndices := xiter.ToSeq2(slices.All([]string{"a", "b", "c"})).
    MapBool(func(k int, _ string) bool { return k%2 == 0 }).
    And()
// false

Not negates each element and returns a new BoolSeq for further chaining:

// no odd numbers in the slice?
noneOdd := xiter.Seq[int](slices.Values([]int{2, 4, 6})).
    MapBool(func(v int) bool { return v%2 != 0 }).
    Not().
    And()
// true

Convert any Seq[bool] directly with BoolSeq(s). Call .Iter() to get back an iter.Seq[bool] for stdlib interop.

Empty sequences: And returns true, Or returns false.

Chaining

Methods return the same wrapper type, so they compose freely:

result := xiter.Seq[int](slices.Values([]int{1, 2, 3, 4, 5, 6, 7, 8})).
    Filter(func(v int) bool { return v%2 == 0 }).
    Skip(1).
    Limit(2).
    Collect()
// []int{4, 6}

Early termination (break inside a range loop) propagates correctly through the chain.

Contributing

See CONTRIBUTING.md.

Security

See SECURITY.md.

Attribution

This library contains some code based on zkr-go-common-public/iter

Documentation

Overview

Package xiter provides iterator utilities for iter.Seq and iter.Seq2.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BoolSeq

type BoolSeq Seq[bool]

BoolSeq is a Seq[bool] with terminal operations And and Or, and the non-terminal Not. Convert any Seq[bool] with BoolSeq(s), or produce one directly from a Seq or Seq2 via MapBool.

func (BoolSeq) And

func (x BoolSeq) And() bool

And returns true if all elements are true. Returns true for an empty sequence.

func (BoolSeq) Iter

func (x BoolSeq) Iter() iter.Seq[bool]

Iter returns the underlying iter.Seq[bool] for interop with stdlib functions.

func (BoolSeq) Not

func (x BoolSeq) Not() BoolSeq

Not returns a BoolSeq with each element negated.

func (BoolSeq) Or

func (x BoolSeq) Or() bool

Or returns true if any element is true. Returns false for an empty sequence.

type Seq

type Seq[V any] func(yield func(V) bool)

Seq is a chainable wrapper around iter.Seq. Convert any iter.Seq[V] with Seq[V](s), then chain methods like Limit.

func ToSeq

func ToSeq[V any](s iter.Seq[V]) Seq[V]

ToSeq converts a standard iter.Seq[V] to Seq[V] for use when type inference is needed.

func Transform

func Transform[V, T any](x Seq[V], f func(V) T) Seq[T]

Transform yields f(v) for each v in x.

In Go 1.27+ (golang/go#77273), this can become a chainable method:

func (x Seq[V]) Transform[T any](f func(V) T) Seq[T] {
    return func(yield func(T) bool) {
        x(func(v V) bool { return yield(f(v)) })
    }
}

func TransformToSeq

func TransformToSeq[K comparable, V, T any](
	x Seq2[K, V], f func(K, V) T,
) Seq[T]

TransformToSeq yields f(k, v) for each (k, v) pair in x.

In Go 1.27+ (golang/go#77273), this can become a chainable method:

func (x Seq2[K, V]) TransformToSeq[T any](f func(K, V) T) Seq[T] {
    return func(yield func(T) bool) {
        x(func(k K, v V) bool { return yield(f(k, v)) })
    }
}

func (Seq[V]) Collect

func (x Seq[V]) Collect() []V

Collect materializes the sequence into a slice.

func (Seq[V]) Filter

func (x Seq[V]) Filter(p func(V) bool) Seq[V]

Filter returns a Seq that yields only elements for which p returns true.

func (Seq[V]) Iter

func (x Seq[V]) Iter() iter.Seq[V]

Iter returns the underlying iter.Seq[V] for interop with stdlib functions.

func (Seq[V]) Limit

func (x Seq[V]) Limit(l uint) Seq[V]

Limit returns a Seq that yields at most l elements then stops iteration.

func (Seq[V]) MapBool

func (x Seq[V]) MapBool(p func(V) bool) BoolSeq

MapBool applies p to each element of x, returning a BoolSeq of the results.

func (Seq[V]) Skip

func (x Seq[V]) Skip(s uint) Seq[V]

Skip returns a Seq that skips the first s elements then yields the rest.

type Seq2

type Seq2[K comparable, V any] func(yield func(K, V) bool)

Seq2 is a chainable wrapper around iter.Seq2. K is constrained to comparable to support Collect into a map.

func ToSeq2

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

ToSeq2 converts a standard iter.Seq2[K, V] to Seq2[K, V] for use when type inference is needed.

func Transform2

func Transform2[K1 comparable, V1 any, K2 comparable, V2 any](
	x Seq2[K1, V1], f func(K1, V1) (K2, V2),
) Seq2[K2, V2]

Transform2 yields f(k, v) for each (k, v) pair in x.

In Go 1.27+ (golang/go#77273), this can become a chainable method:

func (x Seq2[K1, V1]) Transform[K2 comparable, V2 any](
    f func(K1, V1) (K2, V2),
) Seq2[K2, V2] {
    return func(yield func(K2, V2) bool) {
        x(func(k K1, v V1) bool { return yield(f(k, v)) })
    }
}

func TransformToSeq2

func TransformToSeq2[V any, K comparable, V2 any](
	x Seq[V], f func(V) (K, V2),
) Seq2[K, V2]

TransformToSeq2 yields the (K, V2) pair produced by f for each v in x.

In Go 1.27+ (golang/go#77273), this can become a chainable method:

func (x Seq[V]) TransformToSeq2[K comparable, V2 any](
    f func(V) (K, V2),
) Seq2[K, V2] {
    return func(yield func(K, V2) bool) {
        x(func(v V) bool {
            k, v2 := f(v)
            return yield(k, v2)
        })
    }
}

func (Seq2[K, V]) Collect

func (x Seq2[K, V]) Collect() map[K]V

Collect materializes the sequence into a map.

func (Seq2[K, V]) Filter

func (x Seq2[K, V]) Filter(p func(K, V) bool) Seq2[K, V]

Filter returns a Seq2 that yields only pairs for which p returns true.

func (Seq2[K, V]) Iter

func (x Seq2[K, V]) Iter() iter.Seq2[K, V]

Iter returns the underlying iter.Seq2[K, V] for interop with stdlib functions.

func (Seq2[K, V]) Limit

func (x Seq2[K, V]) Limit(l uint) Seq2[K, V]

Limit returns a Seq2 that yields at most l elements then stops iteration.

func (Seq2[K, V]) MapBool

func (x Seq2[K, V]) MapBool(p func(K, V) bool) BoolSeq

MapBool applies p to each (k, v) pair of x, returning a BoolSeq of the results.

func (Seq2[K, V]) Skip

func (x Seq2[K, V]) Skip(s uint) Seq2[K, V]

Skip returns a Seq2 that skips the first s elements then yields the rest.

Jump to

Keyboard shortcuts

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