iterate2

package
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2025 License: GPL-3.0 Imports: 3 Imported by: 0

Documentation

Overview

Package iterate2 builds around iter.Seq2.

Index

Examples

Constants

View Source
const (
	Never         = 0
	InfiniteTimes = -1
)

Useful count constants to use with Repeat.

View Source
const (
	IsReusable    = true
	IsNotReusable = false
)

Determine whether a sequence is reusable when calling Repeat.

Variables

This section is empty.

Functions

func Concatenate

func Concatenate[First any, Second any](sequences ...iter.Seq2[First, Second]) iter.Seq2[First, Second]

Concatenate takes multiple sequences and concatenates them.

If any of the sequences is an infinite sequence, every sequence after that will never have taken values from.

Finite if all underlying iterators are finite, else infinite.

Reusable if all underlying iterators are reusable.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	inputs := [][]string{
		{"Peter", "Paul"},
		{"Mary", "Joannah"},
	}

	for i, s := range iterate2.Concatenate(slices.All(inputs[0]), slices.All(inputs[1])) {
		fmt.Printf("%d: %s\n", i, s)
	}

}
Output:
0: Peter
1: Paul
0: Mary
1: Joannah

func Const added in v1.1.0

func Const[First any, Second any](first First, second Second) func(yield func(First, Second) bool)

Const creates an iterator that returns the same value pair repeatedly.

Infinite iterator. Reusable.

Example
package main

import (
	"fmt"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	count := 0
	for name, age := range iterate2.Const("Someone", 69) {
		count++
		if count > 3 {
			break
		}
		fmt.Printf("%s is %d years old. Nice!\n", name, age)
	}

}
Output:
Someone is 69 years old. Nice!
Someone is 69 years old. Nice!
Someone is 69 years old. Nice!

func Empty added in v1.1.0

func Empty[First any, Second any](_ func(First, Second) bool)

Empty is an iterator which yields no values at all.

Obviously finite and reusable.

func Filter

func Filter[First any, Second any](predicate func(First, Second) bool) func(iter.Seq2[First, Second]) iter.Seq2[First, Second]

Filter yields values from a sequence for which a predicate holds true.

See the pred2 subpackage for pre-defined predicates.

Finiteness and reusability depend on the underlying sequence.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	sumIsEven := func(first int, second int) bool {
		return (first+second)%2 == 0
	}

	values := []int{1, 1, 2, 2, 3, 3}

	for i, n := range iterate2.Filter(sumIsEven)(slices.All(values)) {
		fmt.Printf("index %d + value %d = %d\n", i, n, i+n)
	}

}
Output:
index 1 + value 1 = 2
index 2 + value 2 = 4
index 5 + value 3 = 8

func ForEach

func ForEach[First any, Second any](invoke func(First, Second)) func(iter.Seq2[First, Second])

ForEach invokes a function for every entry from a sequence.

Returns only after exhausting the iterator. Does not return for infinite iterators.

Example
package main

import (
	"fmt"
	"maps"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	people := map[string]int{
		"Peter": 18,
		"Paul":  55,
		"Mary":  32,
	}

	output := func(name string, age int) {
		fmt.Printf("%s is %d years old.\n", name, age)
	}

	iterate2.ForEach(output)(maps.All(people))

}
Output:
Peter is 18 years old.
Paul is 55 years old.
Mary is 32 years old.

func Map

func Map[FirstOutput any, SecondOutput any, Input any](convert func(Input) (FirstOutput, SecondOutput)) func(iter.Seq[Input]) iter.Seq2[FirstOutput, SecondOutput]

Map maps values from an iter.Seq into other values, given a conversion function.

Finiteness and reusability depend on the underlying sequence.

Example
package main

import (
	"fmt"
	"slices"
	"strings"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	input := []string{"a", "baa", "aaaxxx"}

	// convert cuts of "a"s from the front of s, returns whether any were found and the length of the remaining string.
	convert := func(s string) (bool, int) {
		ok := strings.HasPrefix(s, "a")
		s = strings.TrimLeft(s, "a")
		return ok, len(s)
	}

	for ok, n := range iterate2.Map(convert)(slices.Values(input)) {
		if ok {
			fmt.Printf("Some 'a's were removed, rest has length %d.\n", n)
		} else {
			fmt.Printf("No 'a's were removed, length is %d.\n", n)
		}
	}

}
Output:
Some 'a's were removed, rest has length 0.
No 'a's were removed, length is 3.
Some 'a's were removed, rest has length 3.

func Map2

func Map2[FirstOutput any, SecondOutput any, FirstInput any, SecondInput any](convert func(FirstInput, SecondInput) (FirstOutput, SecondOutput)) func(iter.Seq2[FirstInput, SecondInput]) iter.Seq2[FirstOutput, SecondOutput]

Map maps values from an iter.Seq2 into other values, given a conversion function.

Finiteness and reusability depend on the underlying sequence.

Example
package main

import (
	"fmt"
	"maps"
	"strings"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	input := map[string]int{
		"ab":  2,
		"xyz": 1,
		"foo": 3,
	}

	convert := func(s string, n int) (int, string) {
		s = strings.Repeat(s, n)
		return len(s), s
	}

	for n, s := range iterate2.Map2(convert)(maps.All(input)) {
		fmt.Printf("'%s' has length %d.\n", s, n)
	}

}
Output:
'abab' has length 4.
'xyz' has length 3.
'foofoofoo' has length 9.

func OverFunc added in v1.1.0

func OverFunc[First any, Second any](f func() (First, Second)) iter.Seq2[First, Second]

OverFunc creates an iterator that calls f for values.

Infinite iterator. Whether it is reusable or not depends on f.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	var current int = 0
	counter := func() (int, string) {
		current++
		return current, strconv.Itoa(current)
	}

	for intValue, stringValue := range iterate2.OverFunc(counter) {
		if intValue > 3 {
			break
		}
		fmt.Println(intValue, stringValue)
	}

}
Output:
1 1
2 2
3 3

func Reduce

func Reduce[Result any, First any, Second any](initial Result, reducer func(current Result, first First, second Second) Result) func(iter.Seq2[First, Second]) Result

Reduce reduces values from a sequence into a single value.

Do not pass infinite iterators as this would lead to Reduce never returning.

Example
package main

import (
	"fmt"
	"maps"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	f := func(current int, s string, subtract bool) int {
		if subtract {
			return current - len(s)
		}

		return current + len(s)
	}

	inputs := map[string]bool{
		"foo":    false,
		"a":      true,
		"foobar": false,
		"xyz":    true,
	}

	fmt.Println(iterate2.Reduce(0, f)(maps.All(inputs)))

}
Output:
5

func Repeat

func Repeat[First any, Second any](count int, reusable bool) func(iter.Seq2[First, Second]) iter.Seq2[First, Second]

Repeat repeats sequences.

count determines how often the sequence is to be repeated. A value of 0 creates a sequence with no values, a negative value repeats forever. Pass NoRepetition or InfiniteRepetitions for enhanced readability.

reusable determines whether the given iterator can be re-used. If not (and count is not 0), all values from the underlying iterator are stored. Warning: Can lead to unbounded memory usage in case of an infinite iterator.

Example (Infinite)
package main

import (
	"fmt"
	"slices"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	count := 0
	for _, s := range iterate2.Repeat[int, string](iterate2.InfiniteTimes, iterate2.IsReusable)(slices.All([]string{"xyz"})) {
		fmt.Println(s)
		count++
		if count >= 3 {
			break
		}
	}

}
Output:
xyz
xyz
xyz
Example (NotReusable)
package main

import (
	"fmt"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	var exhausted bool

	iterator := func(yield func(number int, name string) bool) {
		if exhausted {
			return
		}

		yield(1, "one")
		yield(2, "two")
		yield(3, "three")

		exhausted = true
	}

	for n, s := range iterate2.Repeat[int, string](2, iterate2.IsNotReusable)(iterator) {
		fmt.Printf("%d -> %s\n", n, s)
	}

}
Output:
1 -> one
2 -> two
3 -> three
1 -> one
2 -> two
3 -> three
Example (Reusable)
package main

import (
	"fmt"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	iterator := func(yield func(name string, age int) bool) {
		yield("Peter", 25)
		yield("Paul", 17)
		yield("Mary", 22)
	}

	for name, age := range iterate2.Repeat[string, int](2, iterate2.IsReusable)(iterator) {
		fmt.Printf("%s is %d years old.\n", name, age)
	}

}
Output:
Peter is 25 years old.
Paul is 17 years old.
Mary is 22 years old.
Peter is 25 years old.
Paul is 17 years old.
Mary is 22 years old.

func Swap

func Swap[First, Second any](sequence iter.Seq2[First, Second]) iter.Seq2[Second, First]

Swap takes a iter.Seq2 and returns a new iter.Seq2 with first and second values swapped.

Example
package main

import (
	"fmt"
	"maps"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	ages := map[string]int{
		"Peter": 33,
		"Paul":  22,
		"Mary":  27,
	}

	for age, name := range iterate2.Swap(maps.All(ages)) {
		fmt.Printf("%s is %d years old.\n", name, age)
	}

}
Output:
Peter is 33 years old.
Paul is 22 years old.
Mary is 27 years old.

func Until added in v1.2.0

func Until[First any, Second any](predicate func(First, Second) bool) func(iter.Seq2[First, Second]) iter.Seq2[First, Second]

Until yields values from a sequence until the given predicate becomes true.

See the pred2 subpackage for pre-defined predicates.

The resulting iterator is finite if the predicate ever becomes true.

Reusable if underlying sequence is reusable.

Example
package main

import (
	"errors"
	"fmt"
	"slices"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	results := slices.All(
		[]error{
			nil,
			nil,
			nil,
			errors.New("broken"),
			nil,
		},
	)

	errorOccured := func(_ int, err error) bool {
		return err != nil
	}

	for i := range iterate2.Until(errorOccured)(results) {
		fmt.Println(i)
	}

}
Output:
0
1
2

func While

func While[First any, Second any](predicate func(First, Second) bool) func(iter.Seq2[First, Second]) iter.Seq2[First, Second]

While yields values from a sequence while a predicate holds true.

See the pred2 subpackage for pre-defined predicates.

Creates finite iterators from infinite iterators.

Reusable if underlying sequence is reusable.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	sumIsLessThan := func(maximum int) func(first int, second int) bool {
		return func(first int, second int) bool {
			return first+second < maximum
		}
	}

	values := []int{2, 3, 5, 7, 11, 13, 17, 19}

	for i, n := range iterate2.While(sumIsLessThan(10))(slices.All(values)) {
		fmt.Printf("index %d + value %d = %d\n", i, n, i+n)
	}

}
Output:
index 0 + value 2 = 2
index 1 + value 3 = 4
index 2 + value 5 = 7

func Zip

func Zip[First any, Second any](firstSequence iter.Seq[First], secondSequence iter.Seq[Second]) iter.Seq2[First, Second]

Zip takes two single-value sequences and zips them into a two-value sequence. If any of the sequences ends, the resulting sequence ends as well. In the case that one sequence ends and the other doesn't, one value from the sequence that did not end is still taken.

If both first sequence and second sequence are infinite, Zip creates an infinite iterator, else it is finite.

Also both sequences need to be reusable for Zip to create a reusable iterator as well.

Example
package main

import (
	"fmt"
	"slices"

	"github.com/GodsBoss/g/seq/iterate2"
)

func main() {
	givenNames := []string{"Peter", "Paul", "Mary"}
	familyNames := []string{"Smith", "Miller", "Doe"}

	zipped := iterate2.Zip(
		slices.Values(givenNames),
		slices.Values(familyNames),
	)

	for givenName, familyName := range zipped {
		fmt.Printf("%s %s\n", givenName, familyName)
	}

}
Output:
Peter Smith
Paul Miller
Mary Doe

Types

This section is empty.

Directories

Path Synopsis
Package pred2 contains predicates for iterate2's Filter() and While() iterators.
Package pred2 contains predicates for iterate2's Filter() and While() iterators.

Jump to

Keyboard shortcuts

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