Documentation ¶
Overview ¶
Package iter implements iteration over sequences, including lazy evaluation.
To avoid confusion, between the higher-order function "map" and the Go map data structure, the former will always be referred to as a "map function" and the latter will always be referred to as a "map collection".
Index ¶
- func All[X any](f func(X) bool, it It[X]) bool
- func Any[X any](f func(X) bool, it It[X]) bool
- func AppendToSlice[X any](dest []X, xs It[X]) []X
- func Check[X any](f func(X) error, it It[X]) error
- func Count[X any](f func(X) bool, it It[X]) (numTrue, numFalse, total int)
- func Exhaust[X any](it It[X])
- func InsertToMap[X comparable, Y any](dest map[X]Y, choose func(key X, original Y, new Y) Y, kvs It[Pair[X, Y]])
- func Join[In any, Out any](j Joiner[In, Out], it It[In]) Out
- func Length[X any](it It[X]) int
- func Reduce[X any](initial X, f func(X, X) X, it It[X]) X
- func ToMap[X comparable, Y any](choose func(key X, original Y, new Y) Y, kvs It[Pair[X, Y]]) map[X]Y
- func ToSlice[X any](xs It[X]) []X
- func ToString(it It[rune]) string
- func Walk[X any](f func(X), it It[X])
- func WalkFinal[X any](f func(X, bool), it It[X])
- type FinalValue
- type It
- func Cat[X any](its ...It[X]) It[X]
- func Counter[I constraints.Integer](start I, step I) It[I]
- func CutString(in string, sep rune) It[string]
- func CutStringStr(in string, sep string) It[string]
- func Empty[X any]() It[X]
- func Enumerate[X any, Y Pair[int, X]](it It[X]) It[Y]
- func Filter[X any](f func(X) bool, it It[X]) It[X]
- func Final[X any](it It[X]) It[FinalValue[X]]
- func FromMap[X comparable, Y any](kvs map[X]Y) It[Pair[X, Y]]
- func FromSlice[X any](xs []X) It[X]
- func FromString(s string) It[rune]
- func Func[X any](f func() (X, bool)) It[X]
- func Keys[X comparable, Y any](xs It[Pair[X, Y]]) It[X]
- func Map[X any, Y any](f func(X) Y, it It[X]) It[Y]
- func Pairwise[X any, Y [2]X](it It[X]) It[Y]
- func PairwiseEnd[X any, Y [2]X](lastValue X, g It[X]) It[Y]
- func Repeat[X any](n int, x X) It[X]
- func Take[X any](n int, xs It[X]) It[X]
- func Tee[X any](n int, g It[X]) []It[X]
- func Values[X comparable, Y any](xs It[Pair[X, Y]]) It[Y]
- func Zip[X any, Y []X](its ...It[X]) It[Y]
- func ZipFlat[X any](its ...It[X]) It[X]
- type Joiner
- type Pair
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func All ¶
All calls function f for each value x produced by an iterator until either f returns false, or the iterator is exhausted. All returns true iff f(x) was true for every x. If the iterator produced no values (was empty), then All still returns true.
func Any ¶
Any calls function f for each value x produced by an iterator until either f(x) returns true, or the iterator is exhausted. It returns true iff f(x) was true for at least one x.
func AppendToSlice ¶
AppendToSlice appends every value produced by an iterator to dest, and returns the modified dest (like the builtin append).
func Check ¶
Check calls function f for each value produced by an iterator. It halts when a non-nil error is returned by f, and immediately returns the error. Otherwise, returns a nil error.
See also Walk, which is similar but does not check for errors.
func Count ¶
Count calls function f for each value x produced by an iterator. It returns a 3-tuple containing a count of the number of times f(x) returned true, a count of the number of times f(x) returned false, and the total number of times f(x) was called. If f is nil, acts as if f(x) => true for all x.
func Exhaust ¶
Exhaust consumes an iterator and discards the produced values. As a special case, a nil iterator safely returns immediately.
func InsertToMap ¶
func InsertToMap[X comparable, Y any]( dest map[X]Y, choose func(key X, original Y, new Y) Y, kvs It[Pair[X, Y]], )
InsertToMap modifies a [builtin.Map] (of Go type map[X]Y, not to be confused with the higher order function Map). For each Pair produced by the input iterator, Pair.Key is used as a map key and Pair.Value is used as the matching value.
If a key already exists in the destination map (either originally, or as a result of the input iterator producing two values with the same key), then the choose function is called with the key, the original value, and the new value. The return value of that function is used as the value to keep. If the choose function is nil, the new value in the case of conflicts is always the one most recently produced by the iterator.
func Reduce ¶
Reduce applies function f to each element of the sequence (in order) with the previous return value from f as the first argument and the element as the second argument (for the first call to f, the supplied initial value is used instead of a return value), returning the final value returned by f.
If the input iterator is empty, the result is the initial value.
func ToMap ¶
func ToMap[X comparable, Y any]( choose func(key X, original Y, new Y) Y, kvs It[Pair[X, Y]], ) map[X]Y
ToMap returns a new [builtin.map] (of Go type map[X]Y, not to be confused with the higher order function Map). For each Pair produced by the input iterator, Pair.Key is used as a map key and Pair.Value is used as the matching value. If the iterator produces two Items with the same Pair.Key, only the last value is kept.
If a key already exists in the destination map (as a result of the input iterator producing two values with the same key), then the choose function is called with the key, the original value, and the new value. The return value of that function is used as the value to keep. If the choose function is nil, the new value in the case of conflicts is always the one most recently produced by the iterator.
Example ¶
package main import ( "fmt" lazy "github.com/tawesoft/golib/v2/iter" ) func main() { type ID string type Person struct { id ID name string age int } // given a list of people, we want a map (id -> person) people := lazy.FromSlice([]Person{ {id: "ATUR001", name: "Alice Turing", age: 23}, {id: "GHOP001", name: "George Hopper", age: 60}, {id: "FKAH001", name: "Freddy Kahlo", age: 29}, }) // for a person input, this function returns (id, person) personToTuple := func(person Person) lazy.Pair[ID, Person] { return lazy.Pair[ID, Person]{person.id, person} } // apply the function over all people (lazily...) peopleTuples := lazy.Map(personToTuple, people) // finally generate a dict peopleByID := lazy.ToMap(nil, peopleTuples) // printer function p := func(lookup map[ID]Person, id ID) { if person, ok := lookup[id]; ok { fmt.Printf("%s: %+v\n", id, person) } else { fmt.Printf("%s: NOT FOUND\n", id) } } p(peopleByID, "ATUR001") }
Output: ATUR001: {id:ATUR001 name:Alice Turing age:23}
func ToSlice ¶
ToSlice returns a slice of every value produced by an iterator. If the input iterator is exhausted, returns an empty slice (not nil).
func Walk ¶
Walk calls a visitor function f for each value produced by an iterator.
See also Check, which is like Walk but aborts on error, and WalkFinal, which is like Walk but the last item produced by the input iterator is detected.
Example ¶
package main import ( "fmt" "strings" lazy "github.com/tawesoft/golib/v2/iter" ) func main() { var sb strings.Builder strings := lazy.FromSlice([]string{"one", "two", "three"}) lazy.Walk(func(x string) { sb.WriteString(x) }, strings) fmt.Println(sb.String()) }
Output: onetwothree
Types ¶
type FinalValue ¶
FinalValue is a value returned by the Final function. Iff IsFinal.IsFinal is true, Value is the last value produced and the iterator is now exhausted.
type It ¶
It is an iterator, defined as a function that produces a (possibly infinite) sequence of (value, true) tuples through successive calls. If the sequence has ended then returned tuple is always (undefined, false).
In this package, an iterator returning a sequence of (value, true) tuples is said to be "producing" values. An iterator returning (undefined, false) is said to be "exhausted". The sequence of values produced by an iterator is said to go from "left to right" where the leftmost value is the first one returned, and the rightmost value is the last one returned. Something that causes an iterator to produce values is called a "consumer". The number of values produced is the length of an iterator. Iterators may have infinite length.
For example, if it := It.FromSlice([]int{1, 2, 3}), then it is an iterator of length three that produces the sequence 1, 2, 3. The leftmost value is 1. The rightmost value is 3. The first call to it() returns (1, true) and is said to have produced the value 1, the second call to it() returns (2, true) and is said to have produced the value 2, the third call to it() returns (3, true) and is said to have produced the value 3, the fourth call to it() returns (0, false) and the iterator is said to be exhausted, and successive calls to it() while exhausted continue to always return (0, false). A second iterator, e.g. it2 := It.Take(5, it1), is an example of an iterator that consumes a production of the input iterator (in this case, it1) whenever it2 produces values.
func Cat ¶
Cat (for "concatenate") returns an iterator that merges several input iterators, consuming an input iterator in its entirety to produce values before moving on to the next input iterator. The input iterators should not be used anywhere else once provided to this function.
For example, given an iterator abc that produces the letters 'a', 'b', 'c', and an iterator def that produces the letters 'd', 'e', 'f', Cat(abc, def) will return an iterator that consumes abc and def to produce the letters 'a', 'b', 'c', 'd', 'e', 'f'.
For an iterator that produces values from each input in lockstep, consuming one value from each iterator in turn, see Zip or ZipFlat.
Some libraries call this function "chain" instead.
func Counter ¶
func Counter[I constraints.Integer](start I, step I) It[I]
Counter returns an iterator that produces a series of integers, starting at the given number, and increasing by step each time. It terminates at the maximum representable value for the number type.
func CutString ¶
CutString is like [Cut], but operates on a string, producing strings delimited by a separator rune.
For example, CutString("a|b|c", "|") returns an iterator that produces the strings "a", "b", "c".
Unlike some Go functions, CutString does not also treat invalid Unicode or invalid Utf8 byte sequences as a valid delimiter when the separator is utf8.RuneError. That is, the utf8.RuneError delimiter only matches bytes that literally encode the Unicode value of utf8.RuneError.
Note that in many situations, it is probably faster, simpler, clearer, and more idiomatic to use a bufio.Scanner. Prefer CutString only if you are combining the result iterator with other higher-order functions in this package.
func CutStringStr ¶
CutStringStr is like CutString, but the delimiter is a string, not just a single rune.
func Enumerate ¶
Enumerate produces a Pair for each value produced by the input iterator, where Pair.Key is an integer that starts at zero and increases by one with each produced value. The input iterator should not be used anywhere else once provided to this function.
For example, for an iterator abc that produces the runes 'a', 'b', 'c', Enumerate(abc) produces the values Pair[0, 'a'], Pair[1, 'b'], Pair[2, 'c'].
func Filter ¶
Filter returns an iterator that consumes an input iterator and only produces those values where the provided filter function f returns true.
As a special case, if f is nil, it is treated as the function f(x) => true.
For example:
function isOdd := func(x int) bool { return x % 2 == 1 } Filter(isOdd, FromSlice([]int{1, 2, 3})) // produces 1 and 3
func Final ¶
func Final[X any](it It[X]) It[FinalValue[X]]
Final produces a FinalValue for each value produced by the input iterator. FinalValue.IsFinal is true iff value is the last value produced before the input iterator would be exhausted. If the input iterator was exhausted at the time of input, then the returned iterator is empty. The input iterators should not be used anywhere else once provided to this function.
For example, Final(FromSlice([]int{1, 2, 3}) produces the values (FinalValue{1, false}, true), (FinalValue{2, false}, true), (FinalValue{3, true}, true), (FinalValue{}, false).
func FromMap ¶
func FromMap[X comparable, Y any](kvs map[X]Y) It[Pair[X, Y]]
FromMap returns an iterator that produces each (key, value) pair from the input [builtin.Map] (of Go type map[X]Y, not to be confused with the higher order function Map) as an Pair. Do not modify the underlying map's keys until no longer using the returned iterator.
Example ¶
package main import ( "fmt" lazy "github.com/tawesoft/golib/v2/iter" ) func main() { type Person struct { name string age int } type ID string // a map of people people := lazy.FromMap(map[ID]Person{ "ATUR001": {name: "Alice Turing", age: 23}, "GHOP001": {name: "George Hopper", age: 60}, "FKAH001": {name: "Freddy Kahlo", age: 29}, }) // this filter function returns true for people under thirty underThirty := func(kv lazy.Pair[ID, Person]) bool { return kv.Value.age < 30 } // apply the filter and finally generate a dict peopleUnderThirty := lazy.ToMap(nil, lazy.Filter(underThirty, people)) // printer function p := func(lookup map[ID]Person, id ID) { if person, ok := lookup[id]; ok { fmt.Printf("%s: %+v\n", id, person) } else { fmt.Printf("%s: NOT FOUND\n", id) } } p(peopleUnderThirty, "ATUR001") p(peopleUnderThirty, "GHOP001") // missing! p(peopleUnderThirty, "FKAH001") }
Output: ATUR001: {name:Alice Turing age:23} GHOP001: NOT FOUND FKAH001: {name:Freddy Kahlo age:29}
func FromSlice ¶
FromSlice returns an iterator that produces each item in the input slice. Do not modify the underlying slice or backing array until no longer using the returned iterator.
func FromString ¶
FromString returns an iterator that produces the runes of string s.
func Func ¶
Func performs a type cast that returns an iterator (type It) from any function meeting the iterator interface.
Example ¶
package main import ( "fmt" lazy "github.com/tawesoft/golib/v2/iter" ) func main() { // generate an infinite sequence of integers with a function integers := func() lazy.It[int] { // or func() func() (int, bool) { i := 0 return func() (int, bool) { result := i i = i + 1 return result, true } } integerGenerator := lazy.Func(integers()) firstFour := lazy.Take(4, integerGenerator) fmt.Printf("First four integers are: %v\n", lazy.ToSlice(firstFour)) }
Output: First four integers are: [0 1 2 3]
func Map ¶
Map returns an iterator that consumes an input iterator (of type X) and produces values (of type Y) for each input value, according to some mapping function f(x X) => y Y.
For example:
double := func(i int) int { return i * 2 } Map(double, FromSlice([int]{1, 2, 3})) // produces 2, 3, 6.
For example, changing the type of the result:
stringify := func(i int) string { return fmt.Sprintf("%d", i) } Map(stringify, FromSlice([int]{1, 2, 3})) // produces "1", "2", "3".
Example ¶
package main import ( "fmt" "strconv" lazy "github.com/tawesoft/golib/v2/iter" ) func main() { numbersAsStrings := lazy.FromSlice([]string{"1", "2", "3", "4"}) // atoi returns the integer x from the string "x" atoi := func(s string) int { i, _ := strconv.Atoi(s) return i } doubler := func(i int) int { return i * 2 } fmt.Printf("%v\n", lazy.ToSlice( lazy.Map[int, int](doubler, // => [2 4 6 8] lazy.Map[string, int](atoi, // => [1 2 3 4] numbersAsStrings)))) // => ["1" "2" "3" "4"] }
Output: [2 4 6 8]
func Pairwise ¶
Pairwise returns an iterator that produces overlapping pairs of values produced by the input. The input iterator should not be used anywhere else once provided to this function.
For example, for an iterator abc that produces the runes 'a', 'b', 'c', Pairwise(abc) produces the pairs [2]rune{'a', b'} and [2]rune{'b', 'c'}.
func PairwiseEnd ¶
PairwiseEnd is like Pairwise, however a final result pair [2]X{value, lastValue} is produced for the last value.
For example, for an iterator abc that produces the runes 'a', 'b', 'c', PairwiseFill(0, abc) produces the pairs [2]rune{'a', b'}, [2]rune{'b', 'c'} and [2]rune{'c', 0}.
func Repeat ¶
Repeat produces the value x, with n repetitions. If n is negative, it produces x with infinite repetitions.
For example, Repeat(3, "foo") produces the values "foo", "foo", "foo".
func Take ¶
Take returns an iterator that produces only (up to) the first n items of the input iterator.
func Tee ¶
Tee returns a slice of n iterators that each, individually, produce the same values otherwise produced by the input iterator. This can be thought of at "copying" an iterator. The input iterators should not be used anywhere else once provided to this function.
For example, given an iterator abc that produces the letters "a", "b", "c", Tee will return n iterators. Each returned iterator will, independently, produce the letters "a", "b", "c".
Where the returned iterators produces their inputs at different speeds (their consumers are "out of step"), this requires growing amounts of auxiliary storage.
func Zip ¶
Zip returns an iterator that produces slices of the results of each input iterator, in lockstep, terminating when any input is exhausted. The input iterators should not be used anywhere else once provided to this function.
For example, for an iterator abc that produces the runes 'a', 'b', 'c', and an input iterator wxyz that produces the runes 'w', 'x', 'y', 'z', Zip(abc, wxyz) produces the values []rune{'a', 'w'}, []rune{'b', 'x'}, []rune{'c', 'y'} before becoming exhausted.
If zipping multiple different types together, you will need to use iterators of type It[any].
func ZipFlat ¶
ZipFlat returns an iterator that produces the results of each input iterator, in turn, terminating when any input is exhausted. The input iterators should not be used anywhere else once provided to this function.
For example, for an iterator abc that produces the runes 'a', 'b', 'c', and an input iterator wxyz that produces the runes 'w', 'x', 'y', 'z', ZipFlat(abc, wxyz) produces the runes 'a', 'w', 'b', 'x', 'c', 'y' before becoming exhausted.
If zipping multiple different types together, you will need to use iterators of type It[any].
Some libraries call this function "round-robin" instead.
type Joiner ¶
Joiner is a type for something that can build a result by walking over an iterator using Join. It must be possible for a Joiner to be used multiple times (although not concurrently) from multiple calls to Join.
type Pair ¶ added in v2.3.0
type Pair[K comparable, V any] struct { Key K Value V }
Pair is any Key, Value pair. Type K is any type that would be suitable as a KeyType in a map collection.