xiter

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2025 License: MIT Imports: 10 Imported by: 13

README

xiter

Go Reference

xiter is a simple implementation of iterator utility functions for Go 1.23's iterators.

Documentation

Overview

Package xiter provides iterator-related functionality compatible with, but not requiring, Go 1.23.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func All

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

All returns true if f(element) is true for every element of seq.

func Any

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

Any returns true if f(element) is true for any elements of seq.

func AppendSplitTo

func AppendSplitTo[T1, T2 any](seq SplitSeq[T1, T2], s1 []T1, s2 []T2) ([]T1, []T2)

AppendSplitTo collects the elements of seq by appending them to existing slices.

func Bytes

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

Bytes returns a Seq over the bytes of s.

func Cache

func Cache[T any](seq iter.Seq[T]) iter.Seq[T]

Cache returns a Seq that can be iterated more than once. On the first iteration, it yields the values from seq and caches them. On subsequent iterations, it yields the cached values from the first iteration.

func Chunks

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

Chunks works just like Windows except that the yielded slices of elements do not overlap. In other words,

Chunks(Generate(0, 1), 3)

will yield

[0, 1, 2]
[3, 4, 5]
[6, 7, 8]

Like with Windows, the slice is reused between iterations.

func ChunksFunc

func ChunksFunc[T any, C comparable](seq iter.Seq[T], chunker func(T) C) iter.Seq[[]T]

ChunksFunc is like Chunks, except chunk boundaries are determined by calling chunker on successive elements. When the return value of the function changes from the previous call, a new chunk is started.

Like with Chunks, the slice is reused between iterations.

func CollectSize

func CollectSize[T any](seq iter.Seq[T], len int) []T

CollectSize pre-allocates the slice being collected into to the given size. It is provided purely for convenience.

func CollectSplit

func CollectSplit[T1, T2 any](seq SplitSeq[T1, T2]) (y1 []T1, y2 []T2)

CollectSplit is like [Collect], but for a SplitSeq.

func Concat

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

Concat creates a new Seq that yields the values of each of the provided Seqs in turn.

func Contains

func Contains[T comparable](seq iter.Seq[T], v T) bool

Contains returns true if v is an element of seq.

func Dedup

func Dedup[T comparable](seq iter.Seq[T]) iter.Seq[T]

Dedup returns an iterator that only yields each unique element from seq once. Note that to do this, it stores a set of all elements that have been seen, so this iterator can use a large amount of memory if seq yields a very large number of unique elements.

func Drain

func Drain[T any](seq iter.Seq[T]) (v T, ok bool)

Drain empties seq, returning the last value yielded. If no values are yielded, ok will be false.

func Enumerate

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

Enumerate returns a Seq2 that counts the number of iterations of seq as it yields elements from it, starting at 0.

func Equal

func Equal[T cmp.Ordered](seq1, seq2 iter.Seq[T]) bool

Equal returns true if seq1 and seq2 are the same length and each element of each is equal to the element at the same point in the sequence of the other.

func EqualFunc

func EqualFunc[T1, T2 any](seq1 iter.Seq[T1], seq2 iter.Seq[T2], equal func(T1, T2) bool) bool

EqualFunc is like Equal but uses a custom comparison function to determine the equivalence of the elements of each sequence.

func Filter

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

Filter returns a Seq that yields only the values of seq for which f(value) returns true.

func Find

func Find[T any](seq iter.Seq[T], f func(T) bool) (r T, ok bool)

Find returns the first value of seq for which f(value) returns true.

func Flatten

func Flatten[T any](seq iter.Seq[iter.Seq[T]]) iter.Seq[T]

Flatten yields all of the elements of each Seq yielded from seq in turn.

func Fold

func Fold[T any](seq iter.Seq[T], reducer func(T, T) T) T

Fold performs a Reduce but uses the first value yielded by seq instead of a provided initial value. If seq doesn't yield any values, the zero value of T is returned.

func FromPair

func FromPair[T1, T2 any](seq iter.Seq[Pair[T1, T2]]) iter.Seq2[T1, T2]

FromPair converts a Seq of pairs to a two-value Seq.

func Generate

func Generate[T Addable](start, step T) iter.Seq[T]

Generate returns a Seq that first yields start and then yields successive values by adding step to the previous continuously. The returned Seq does not end. To limit it to a specific number of returned elements, use Limit.

func Handle

func Handle[T any](seq iter.Seq2[T, error], f func(error) bool) iter.Seq[T]

Handle splits seq by calling f for any non-nil errors yielded by seq. If f returns false, iteration stops. If an iteration's error is nil or f returns true, the other value is yielded by the returned Seq.

TODO: This is significantly less useful than it could be. For example, there's no way to tell it to skip the yield but continue iteration anyways.

func IsSorted

func IsSorted[T cmp.Ordered](seq iter.Seq[T]) bool

IsSorted returns true if each element of seq is greater than or equal to the previous one.

func IsSortedFunc

func IsSortedFunc[T any](seq iter.Seq[T], compare func(T, T) int) bool

IsSortedFunc is like IsSorted but uses a custom comparison function.

func Limit

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

Limit returns a Seq that yields at most n values from seq.

func Map

func Map[T1, T2 any](seq iter.Seq[T1], f func(T1) T2) iter.Seq[T2]

Map returns a Seq that yields the values of seq transformed via f.

func Max

func Max[T cmp.Ordered](seq iter.Seq[T]) T

Max returns maximum element yielded by seq or the zero value if seq doesn't yield anything.

func Merge

func Merge[T cmp.Ordered](seq1, seq2 iter.Seq[T]) iter.Seq[T]

Merge returns a sequence that yields values from the ordered sequences seq1 and seq2 one at a time to produce a new ordered sequence made up of all of the elements of both seq1 and seq2.

func MergeFunc

func MergeFunc[T any](seq1, seq2 iter.Seq[T], compare func(T, T) int) iter.Seq[T]

MergeFunc is like Merge, but uses a custom comparison function for determining the order of values.

func Min

func Min[T cmp.Ordered](seq iter.Seq[T]) T

Min returns the minimum element yielded by seq or the zero value if seq doesn't yield anything.

func Of

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

Of returns a Seq that yields the provided values.

func OfChan

func OfChan[T any](c <-chan T) iter.Seq[T]

OfChan returns a Seq which yields values received from c. The sequence ends when c is closed. It is equivalent to range c.

func Or

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

Or yields all of the values from the first Seq which yields at least one value and then stops.

func Partition

func Partition[T any](seq iter.Seq[T], f func(T) bool) (true, false []T)

Partition returns two slices, one containing all of the elements of seq for which f(element) is true and one containing all of those for which it is false.

func PartitionInto

func PartitionInto[T any](seq iter.Seq[T], f func(T) bool, true, false []T) ([]T, []T)

PartitionInto performs a Partition by appending to two existing slices.

func Product

func Product[T Multiplyable](seq iter.Seq[T]) T

Product returns the values of seq multiplied together. It returns 1 if no values are yielded.

func Push added in v0.2.1

func Push[In, Out any](coroutine func(iter.Seq[In]) Out) (yield func(In) bool, stop func() Out)

Push is the opposite, in some ways, of iter.Pull. Where iter.Pull creates a coroutine from which values can be yielded, Push creates a coroutine into which values can be yielded. This is useful for wrapping certain types of APIs to make them interact more cleanly with iter.Seq, like that shown in the example.

If full, two-way communication with coroutine is necessary, see Coroutine.

Example
package main

import (
	"fmt"

	"deedles.dev/xiter"
)

type Aggregate[S, R any] interface {
	Step(S)
	Result() R
}

type aggregate struct {
	next func(int) bool
	stop func() int
}

func (s *aggregate) Step(v int) {
	if s.next != nil {
		if !s.next(v) {
			s.next = nil
		}
	}
}

func (s *aggregate) Result() int { return s.stop() }

func main() {
	// This example demonstrates creating an implementation of an
	// interface that wraps an iter.Seq in a roundabout way. This is
	// useful for handling cases where some API provides an interface
	// that the user must implement but that does not map cleanly to the
	// iter.Seq API.

	yield, stop := xiter.Push(xiter.Sum[int])
	s := &aggregate{next: yield, stop: stop}

	// This simulates the API using sum via the interface.
	for n := range 10 {
		s.Step(n)
	}
	fmt.Println(s.Result())
}
Output:

45

func ReadBytes

func ReadBytes(r io.ByteReader) iter.Seq2[byte, error]

ReadBytes returns an iterator over the bytes of r. If reading the next byte returns an error, the iterator will yield a non-nil error and then exit.

func ReadRunes

func ReadRunes(r io.RuneReader) iter.Seq2[rune, error]

ReadRunes returns an iterator over the runes of r. If reading the next rune returns an error, the iterator will yield a non-nil error and then exit.

func RecvContext

func RecvContext[T any](ctx context.Context, c <-chan T) iter.Seq[T]

RecvContext returns a Seq that receives from c continuously until either c is closed or the given context is canceled.

func Reduce

func Reduce[T, R any](seq iter.Seq[T], initial R, reducer func(R, T) R) R

Reduce calls reducer on each value of seq, passing it initial as its first argument on the first call and then the result of the previous call for each call after that. It returns the final value returned by reducer.

Reduce can be somewhat complicated to get the hang of, but very powerful. For example, a simple summation of values can be done as

sum := Reduce(seq, 0, func(total, v int) int { return total + v })

func Runes

func Runes[T ~[]byte | ~string](s T) iter.Seq[rune]

Runes returns a Seq over the runes of s.

func ScanBytes

func ScanBytes(r io.ByteScanner) iter.Seq2[byte, error]

ScanBytes returns an iterator over the bytes of r. If reading the next byte returns an error, the iterator will yield a non-nil error and then exit.

If the iterator is terminated early, it will unread the last byte read, allowing it to be used again to continue from where it left off. If this is not the desired behavior, use ReadBytes instead.

func ScanRunes

func ScanRunes(r io.RuneScanner) iter.Seq2[rune, error]

ScanRunes returns an iterator over the runes of r. If reading the next rune returns an error, the iterator will yield a non-nil error and then exit.

If the iterator is terminated early, it will unread the last rune read, allowing it to be used again to continue from where it left off. If this is not the desired behavior, use ReadRunes instead.

func SendContext

func SendContext[T any](seq iter.Seq[T], ctx context.Context, c chan<- T)

SendContext sends values from seq to c repeatedly until either the sequence ends or ctx is canceled. It blocks until one of those two things happens.

func Skip

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

Skip returns a Seq that skips over the first n elements of seq and then yields the rest normally.

func SliceChunksFunc

func SliceChunksFunc[T any, C comparable, S ~[]T](s S, chunker func(T) C) iter.Seq[S]

SliceChunksFunc is like ChunksFunc but operates on a slice instead of an iter.Seq. When dealing with data that is in a slice, this is more effecient than using ChunksFunc as it can yield subslices of the underlying slice instead of having to allocate a moving window. The yielded subslices have their capacity clipped.

func Sorted added in v0.1.1

func Sorted[T cmp.Ordered](seq iter.Seq[T]) iter.Seq[T]

Sorted collects the entirety of seq and then returns a one-time use iterator which yields the elements of seq in a sorted order.

func SortedFunc added in v0.1.1

func SortedFunc[T any](seq iter.Seq[T], compare func(T, T) int) iter.Seq[T]

SortedFunc collects the entirety of seq and then returns a one-time use iterator which yields the elements of seq in a sorted order determined by the provided comparison function.

func StringFields

func StringFields(s string) iter.Seq[string]

StringFields returns an iterator over the substrings of s that are seperated by consecutive whitespace as determined by unicode.IsSpace. It is very similar to strings.Fields.

func StringFieldsFunc

func StringFieldsFunc(s string, sep func(rune) bool) iter.Seq[string]

StringFieldsFunc returns an iterator over the substrings of s that are seperated by consecutive sections of runes for which sep returns true. It behaves very similarly to strings.FieldsFunc.

func StringJoin

func StringJoin(seq iter.Seq[string], sep string) string

StringJoin works exactly like strings.Join but it operates on an iter.Seq instead of a []string.

func StringSplit

func StringSplit(s, sep string) iter.Seq[string]

StringSplit returns an iterator over the substrings of s that are separated by sep. It behaves very similarly to strings.Split.

func Sum

func Sum[T Addable](seq iter.Seq[T]) T

Sum returns the values of seq added together in the order that they are yielded.

func ToPair

func ToPair[T1, T2 any](seq iter.Seq2[T1, T2]) iter.Seq[Pair[T1, T2]]

ToPair takes a two-value iterator and produces a single-value iterator of pairs.

func Uniq

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

Uniq returns an iterator that removes consecutive duplicates from seq. It is similar to Dedup, but non-consecutive duplicates are not filtered out. Unlike Dedup, it does not store all found values, and so does not have the same performance implication that Dedup does.

func UniqFunc

func UniqFunc[T comparable](seq iter.Seq[T], eq func(T, T) bool) iter.Seq[T]

UniqFunc is like Uniq but uses the provided comparison function to check for duplicates.

func V1

func V1[T1, T2 any](seq iter.Seq2[T1, T2]) iter.Seq[T1]

V1 returns a Seq which iterates over only the T1 elements of seq.

func V2

func V2[T1, T2 any](seq iter.Seq2[T1, T2]) iter.Seq[T2]

V2 returns a Seq which iterates over only the T2 elements of seq.

func Windows

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

Windows returns a slice over successive overlapping portions of size n of the values yielded by seq. In other words,

Windows(Generate(0, 1), 3)

will yield

[0, 1, 2]
[1, 2, 3]
[2, 3, 4]

and so on. The slice yielded is reused from one iteration to the next, so it should not be held onto after each iteration has ended. Map and slices.Clone may come in handy for dealing with situations where this is necessary.

func Zip

func Zip[T1, T2 any](seq1 iter.Seq[T1], seq2 iter.Seq[T2]) iter.Seq[Zipped[T1, T2]]

Zip returns a new Seq that yields the values of seq1 and seq2 simultaneously.

Types

type Addable

type Addable interface {
	int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr | float32 | float64 | complex64 | complex128 | string
}

Addable is a type that should probably exist in the standard library somewhere because it's quite common and kind of a pain to write every time I need it.

type CoroutineFunc

type CoroutineFunc[In, Out any] = func(first In, yield CoroutineYieldFunc[Out, In]) Out

CoroutineFunc is the signature of a coroutine function as passed to Coroutine.

type CoroutineYieldFunc

type CoroutineYieldFunc[In, Out any] = func(In) (Out, bool)

CoroutineYieldFunc is the signature of a coroutine yield function as returned by Coroutine.

func Coroutine

func Coroutine[In, Out any](coroutine CoroutineFunc[In, Out]) (yield CoroutineYieldFunc[In, Out], stop func() Out)

Coroutine starts the provided function as a coroutine. This is similar to a pull iterator as returned by iter.Pull, but allows full, two-way communication with the suspended function. The returned yield function can be used to pass data into the coroutine, while the function given to the coroutine function itself can be used to pass data back out, suspending the coroutine where it was. All of the caveats and warnings that apply to iter.Pull also apply to this.

Coroutine is a somewhat complicated function with a lot of nested function types that can be kind of confusing to work with. For a simpler function that can handle some cases that Coroutine might be necessary for, see Push.

The coroutine provided is not started until the first call to the returned yield function. On the first call, the coroutine is called with the data passed to yield as its first argument. All subsequent calls to yield will cause the yield function inside of the coroutine to return the data provided instead.

The returned stop function returns the final return value of the coroutine function. If the coroutine was never started, this will return the zero value.

After stop is called, the value returned by yield inside of the coroutine will be the last value that was yielded to the coroutine before the call to stop.

Example
next, stop := Coroutine(func(val int, next func(int) (int, bool)) int {
	for {
		v, ok := next(val * 2)
		if !ok {
			return v
		}
		val = v
	}
})
defer stop()

var val int
for range 10 {
	v, ok := next(val + 1)
	if !ok {
		break
	}
	val = v
}
fmt.Printf("result: %v\n", stop())
Output:

result: 1023

type Multiplyable

type Multiplyable interface {
	int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr | float32 | float64 | complex64 | complex128
}

type Pair

type Pair[T1, T2 any] struct {
	V1 T1
	V2 T2
}

Pair contains two values of arbitrary types.

func P

func P[T1, T2 any](v1 T1, v2 T2) Pair[T1, T2]

P returns a Pair containing v1 and v2.

func (Pair[T1, T2]) Split

func (p Pair[T1, T2]) Split() (T1, T2)

Split is a convenience function that just returns the two values contained in the pair.

type SplitSeq

type SplitSeq[T1, T2 any] func(y1 func(T1) bool, y2 func(T2) bool)

A SplitSeq is like a Seq but can yield via either of two functions. It might not be useful, but is included anyways because it might be.

func Split

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

Split returns a SplitSeq which yields the values of seq for which f(value) is true to its first yield function and the rest to its second.

func Split2

func Split2[T1, T2 any](seq iter.Seq2[T1, T2]) SplitSeq[T1, T2]

Split2 transforms a Seq2 into a SplitSeq. Every iteration of the Seq2 yields both values via the SplitSeq.

type Zipped

type Zipped[T1, T2 any] struct {
	V1  T1
	OK1 bool

	V2  T2
	OK2 bool
}

Zipped holds values from an iteration of a Seq returned by Zip.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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