iter

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 29, 2025 License: Apache-2.0 Imports: 14 Imported by: 0

README

iter - Iterator and Operations

  • Import Path

    import "github.com/bytedance/gg/internal/iter"

Package iter provides definition of generic iterator Iter and high-order functions for operating it. Most of the operations are lazy.

  • Iterator helps us you iterating various data structure in same way.
  • “Operation” is operation for processing elements of iterator.
  • “Lazy” means that the evaluation of an operation is delayed until its value is needed

We can create iterator from Golang’s slice, map or even channel, and apply various operations on it.

Beside, user can Implement your custom Iter.

This packages is greatly inspired by Haskell.

Quick Start

  1. Import "github.com/bytedance/gg/internal/iter".
  2. Use FromSlice source to create a iterator of int slice.
  3. Use Filter operation to filter the zero values.
  4. Use Map operation to convert int to string.
  5. Use ToSlice sink to convert elements of iterator to slice, evaluation is done here.
package main

import (
        "fmt"

        "github.com/bytedance/gg/gvalue"
        "github.com/bytedance/gg/internal/iter"
)

func main() {
        s := iter.ToSlice(
                iter.Map(strconv.Itoa,
                        iter.Filter(gvalue.IsZero[int],
                                iter.FromSlice([]int{0, 1, 2, 3, 4}))))
        fmt.Printf("%q\n", s)

        // Output:
        // ["1" "2" "3" "4"]
}

API References

Sources

Source is used to craete iterator from data (like slice, map, and etc). Source functions are usually named “FromXxx” if “Xxx” is a noun.

Data Sources
Slice FromSlice
Map FromMap, FromMapKeys, FromMapValues
Channel FromChan
Others Range, RangeWithStep, Repeat
Sinks

Sink is used to extract iterator to data (like slice, map, and etc). Sink functions are usually named “ToXxx”.

Data Sinks
Slice ToSlice
Map ToMap
Channel ToChan, ToBufferedChan
Operations

Operation is used to process elements of iterator.

General

These operations can be applied on iterator of any type:

Kind Operations
Map Map, MapInplace, FlatMap, Cast, FilterMap
Filter Filter, Find, DistinctWith, DistinctOrderedWith
Fold Fold, FoldWith, Count, All, Any
Iteration ForEach, ForEachIndexed
Substream Take, Drop, TakeWhile, DropWhile
List Head, Last, Reverse, Prepend, Append, Concat, Intersperse, SortWith, At, Chunk
Zipping Zip, ZipWith
Type-specified

These operations can only be applied on iterator of specified type:

Type Usage
comparable Contains, Distinct, DistinctOrdered, Remove, RemoveN
constraints.Ordered Max, Min, Sort
~bool And, Or
~string Join
constraints.Integer | constraints.Float Sum, Avg

Tips

Use method chaining

As we see, operations are functions. We have to nest function calls when we have multiple operations to be applied (as we do in Quick Start).

Method chaining is a convenient style for simplifying nested calls. stream - Stream Processing provides a series of iterator wrappers with method chaining support.

Operating Custom Data

If you want to apply operation on data structures which are not included in Sources just implement an Iter interface for them. Take container/list as an example:

Implement Iter interface for container/list:

import (
        "container/list"
)

type listIter[T any] struct {
        e *list.Element
}

func FromList[T any](l *list.List) Iter[T] {
        return &listIter[T]{l.Front()}
}

func (i *listIter[T]) Next(n int) []T {
        var next []T
        j := 0
        for i.e != nil {
                next = append(next, i.e.Value.(T))
                i.e = i.e.Next()
                j++
                if n != ALL && j >= n {
                        break
                }
        }
        return next
}

Then you can apply various operations:

l := list.New()
l.PushBack(0)
l.PushBack(1)
l.PushBack(2)

l := list.New()
l.PushBack(0)
l.PushBack(1)
l.PushBack(2)

i := FromList(l)
s := ToSlice(Filter(gvalue.IsZero[int], i))
fmt.Println(s)

// Output:
// [1 2]
Partial Application

partial - Partial Application implements Partial Application which can simplify our use of higher-order functions:

add := gvalue.Add[int]                 // instantiate a int version of Add function
add1 := gfunc.Partial2(add).Partial(1) // bind the first argument to 1
s := ToSlice(
        Map(add1,
            FromSlice([]int{1, 2, 3, 4})))

fmt.Println(s)
// Output:
// [2 3 4 5]
Generics Utils

gvalue provides a lots of helpful functions and predicates with generics support.

Documentation

Overview

Package iter provides definition of generic iterator Iter and high-order functions.

Please refer to README.md for details.

Example

Convert an int slice to string slice.

s := ToSlice(
	Map(strconv.Itoa,
		Filter(gvalue.IsNotZero[int],
			FromSlice([]int{0, 1, 2, 3, 4}))))
fmt.Printf("%q\n", s)
Output:

["1" "2" "3" "4"]

Index

Examples

Constants

View Source
const (
	ALL = -1
)

Variables

This section is empty.

Functions

func All

func All[T any](f func(T) bool, i Iter[T]) bool

All determines whether all elements of the iterator i satisfy the predicate f.

func And

func And[T ~bool](i Iter[T]) bool

And determines whether all elements of the iterator i are true.

func Any

func Any[T any](f func(T) bool, i Iter[T]) bool

Any determines whether any (at least one) element of the iterator i satisfies the predicate f.

Any supports short-circuit evaluation.

func At

func At[T any](idx int, i Iter[T]) (r goption.O[T])

At returns the possible element at given 0-based index idx.

⚠️ WARNING: Panic when index < 0.

func Avg

func Avg[T constraints.Number](i Iter[T]) float64

Avg returns the arithmetic mean of elements of iterator i.

func AvgBy

func AvgBy[T any, N constraints.Number](f func(T) N, i Iter[T]) float64

AvgBy applies function f to each element of iterator i, returns the arithmetic mean of function result.

func Contains

func Contains[T comparable](v T, i Iter[T]) bool

Contains returns whether the element occur in iterator.

func ContainsAll

func ContainsAll[T comparable](vs []T, i Iter[T]) bool

ContainsAll returns whether the all of given elements occur in iterator.

func ContainsAny

func ContainsAny[T comparable](vs []T, i Iter[T]) bool

ContainsAny returns whether the any one of given elements occur in iterator.

func Count

func Count[T any](i Iter[T]) int

Count returns the count of elements of iterator.

func Find

func Find[T any](f func(T) bool, i Iter[T]) (r goption.O[T])

Find returns the possible first element of iterator that satisfies predicate f.

func Fold

func Fold[T1, T2 any](f func(T1, T2) T1, init T1, i Iter[T2]) T1

Fold applies function f cumulatively to each element of iterator i, so as to fold the Iter to a single value.

An init element is needed as the initial value of accumulation.

func ForEach

func ForEach[T any](f func(v T), i Iter[T])

ForEach applies function f to each element of iterator i.

func ForEachIndexed

func ForEachIndexed[T any](f func(i int, v T), i Iter[T])

ForEachIndexed applies function f to each element of iterator i. The argument i of function f represents the zero-based index of that element of iterator.

func GroupBy

func GroupBy[K comparable, T any](f func(T) K, i Iter[T]) map[K][]T

GroupBy groups adjacent elements according to key returned by function f.

func Head[T any](i Iter[T]) (r goption.O[T])

Head extracts the first element of iterator i.

func Join

func Join[T ~string](sep T, i Iter[T]) T

Join joins all elements in iterator i into a string with value sep as separator.

func KVToMap

func KVToMap[K comparable, V any](i Iter[tuple.T2[K, V]]) map[K]V

KVToMap collects elements of iterator to a map.

If the iterator is empty, empty map map[K]V{} is returned.

func Max

func Max[T constraints.Ordered](i Iter[T]) (r goption.O[T])

Max returns the maximum element of iterator i.

func MaxBy

func MaxBy[T any](less func(T, T) bool, i Iter[T]) (r goption.O[T])

MaxBy returns the maximum element of iterator i determined by function less.

func Min

func Min[T constraints.Ordered](i Iter[T]) (r goption.O[T])

Min returns the minimum element of iterator i.

func MinBy

func MinBy[T any](less func(T, T) bool, i Iter[T]) (r goption.O[T])

MinBy returns the minimum element of iterator i determined by function less.

func MinMax

func MinMax[T constraints.Ordered](i Iter[T]) (r goption.O[tuple.T2[T, T]])

MinMax returns both minimum and maximum elements of iterator i.

💡 NOTE: The returned min and max elements may be the same object when each element of the iterator is equal

💡 AKA: Bound

func MinMaxBy

func MinMaxBy[T any](less func(T, T) bool, i Iter[T]) (r goption.O[tuple.T2[T, T]])

MinMaxBy returns both minimum and maximum elements of iterator i determined by function less.

💡 AKA: BoundBy

func Or

func Or[T ~bool](i Iter[T]) bool

Or determines whether any (at least one) element of the iterator i is true.

Or supports short-circuit evaluation.

func Reduce

func Reduce[T any](f func(T, T) T, i Iter[T]) (r goption.O[T])

Reduce is a variant of Fold, use the first element of iterator as the initial value of accumulation.

func Sum

func Sum[T constraints.Number](i Iter[T]) T

Sum returns the arithmetic sum of the elements of iterator i.

💡 NOTE: The returned type is still T, it may overflow for smaller types (such as int8, uint8).

func SumBy

func SumBy[T any, N constraints.Number](f func(T) N, i Iter[T]) N

SumBy applies function f to each element of iterator i, returns the arithmetic sum of function result.

func ToBufferedChan

func ToBufferedChan[T any](ctx context.Context, size int, i Iter[T]) <-chan T

ToBufferedChan collects elements of iterator to a buffered chan with given size.

The returned channel will be closed when iterator is exhausted.

func ToChan

func ToChan[T any](ctx context.Context, i Iter[T]) <-chan T

ToChan collects elements of iterator to a chan. The returned channel will be closed when iterator is exhausted.

func ToMap

func ToMap[K comparable, V, T any](f func(T) (K, V), i Iter[T]) map[K]V

ToMap collects elements of iterator i to a map, both map keys and values are produced by mapping function f.

If the iterator is empty, empty map map[K]V{} is returned.

func ToMapValues

func ToMapValues[K comparable, T any](f func(T) K, i Iter[T]) map[K]T

ToMapValues collects elements of iterator to values of map, the map keys are produced by mapping function f.

If the iterator is empty, empty map map[K]T{} is returned.

func ToSlice

func ToSlice[T any](i Iter[T]) []T

ToSlice collects elements of iterator to a slice.

If the iterator is empty, empty slice []T{} is returned.

Types

type Iter

type Iter[T any] interface {
	// Next returns N items of iterator when it is not empty.
	// When the iterator is empty, nil is returned.
	// When n = [ALL] or n is greater than the number of remaining elements,
	// all remaining are returned.
	//
	// The returned slice is owned by caller. So implementer should return a
	// newly allocated slice if needed.
	//
	// Passing in a negative n (except [ALL]) is undefined behavior.
	Next(n int) []T
}

Iter is a generic iterator interface, which helps us iterate various data structures in the same way.

Users can apply various operations (Map, Filter, etc.) on custom data structures by implementing Iter for them. See ExampleIter_impl for details.

Example (Impl)

Iter for container list.

l := list.New()
l.PushBack(0)
l.PushBack(1)
l.PushBack(2)

s := ToSlice(
	Filter(gvalue.IsNotZero[int],
		FromList[int](l)))
fmt.Println(s)
Output:

[1 2]

func Append

func Append[T any](tail T, i Iter[T]) Iter[T]

Append appends value tail to iterator i.

func Chunk

func Chunk[T any](n int, i Iter[T]) Iter[[]T]

Chunk splits a list into length-n chunks and returns chunks by a new iterator.

The last chunk will be shorter if n does not evenly divide the length of the iterator.

💡 HINT: If you want to splits list into n chunks, use function Divide.

func Compact

func Compact[T comparable](i Iter[T]) Iter[T]

Compact removes all zero value from given iterator i, returns a new iterator.

💡 HINT: See github.com/bytedance/gg/gvalue.Zero for details of zero value.

func Concat

func Concat[T any](is ...Iter[T]) Iter[T]

Concat concats all the elements of iterators.

func Divide

func Divide[T any](n int, i Iter[T]) Iter[[]T]

Divide splits a list into exactly n chunks and returns chunks by a new iterator.

The length of chunks will be different if n does not evenly divide the length of the iterator.

💡 HINT: If you want to splits list into length-n chunks, use function Chunk.

func Drop

func Drop[T any](n int, i Iter[T]) Iter[T]

Drop drops the first n elements of iterator, returns the remaining part of slice, or empty iterator if n > len(s).

⚠️ WARNING: Panic when n < 0.

func DropWhile

func DropWhile[T any](f func(T) bool, i Iter[T]) Iter[T]

DropWhile returns the elements when the predicate f fails for the first time till the end of the iterator.

In other words, it returns the suffix remaining after TakeWhile(f, i).

func Dup

func Dup[T comparable](i Iter[T]) Iter[T]

Dup returns the repeated elements of iterator. The result is a new iterators contains duplicate elements.

func DupBy

func DupBy[T any, K comparable](f func(T) K, i Iter[T]) Iter[T]

DupBy distinguishes repeated elements with key function f, returns the duplicate elements of iterator. The result is a new iterators contains duplicate elements.

func Filter

func Filter[T any](f func(T) bool, i Iter[T]) Iter[T]

Filter applies predicate f to each element of iterator i, returns those elements that satisfy the predicate f as a new Iter.

func FilterMap

func FilterMap[T1, T2 any](f func(T1) (T2, bool), i Iter[T1]) Iter[T2]

FilterMap applies function f to each element of iterator i with Type T1. If f return false, the element i will be removed Results of f are returned as a new Iter with Type T2.

func FlatMap

func FlatMap[T1, T2 any](f func(T1) []T2, i Iter[T1]) Iter[T2]

FlatMap applies function f to each element of iterator i with Type T1. Results of f are flattened and returned as a new Iter with Type T2.

func FromChan

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

FromChan constructs an Iter from channel ch. Elements in Iter are exhausted when the context is done or given channel is closed. FIXME: better doc

func FromMap

func FromMap[K comparable, V any](m map[K]V) Iter[tuple.T2[K, V]]

FromMap constructs an Iter of (key, value) pair from map m.

💡 NOTE: Function follows the same iteration semantics as a range statement. See https://go.dev/blog/maps#iteration-order for details.

func FromMapKeys

func FromMapKeys[K comparable, V any](m map[K]V) Iter[K]

FromMapKeys constructs an Iter of map's key from map m.

💡 NOTE: Function follows the same iteration semantics as a range statement. See https://go.dev/blog/maps#iteration-order for details.

func FromMapValues

func FromMapValues[K comparable, V any](m map[K]V) Iter[V]

FromMapValues constructs an Iter of map's value from map m.

💡 NOTE: Function follows the same iteration semantics as a range statement. See https://go.dev/blog/maps#iteration-order for details.

func FromSlice

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

FromSlice constructs an Iter from slice s, in order from left to right. An empty Iter (without element) is returned if the given slice is empty or nil.

func Intersperse

func Intersperse[T any](sep T, i Iter[T]) Iter[T]

Intersperse intersperses value sep between the elements of iterator i.

func Map

func Map[T1, T2 any](f func(T1) T2, i Iter[T1]) Iter[T2]

Map applies function f to each element of iterator i with Type T1. Results of f are returned as a new Iter with Type T2.

func MapInplace

func MapInplace[T any](f func(T) T, i Iter[T]) Iter[T]

MapInplace is a closed Map operation, applies function f to each element. Results of f are returned as a new iterator with same type.

💡 HINT: MapInplace can reuse the underlying buffer of iterator, so it is more efficient than Map.

func Prepend

func Prepend[T any](head T, i Iter[T]) Iter[T]

Prepend prepends value head to iterator i.

func Range

func Range[T constraints.Number](start, stop T) Iter[T]

Range is a variant of RangeWithStep, with predefined step 1.

func RangeWithStep

func RangeWithStep[T constraints.Number](start, stop, step T) Iter[T]

RangeWithStep constructs an Iter of number from start (inclusive) to stop (exclusive) by step. If the interval does not exist, RangeWithStep returns an emptyIter.

func Remove

func Remove[T comparable](v T, i Iter[T]) Iter[T]

Remove removes all element v from the iterator i, returns a new iterator.

func RemoveN

func RemoveN[T comparable](v T, n int, i Iter[T]) Iter[T]

Remove removes the first N element v from the iterator i, returns a new iterator.

func Repeat

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

Repeat constructs an infinite Iter, with v the value of every element.

func Reverse

func Reverse[T any](i Iter[T]) Iter[T]

Reverse reverses the elements of iterator i.

func Shuffle

func Shuffle[T any](i Iter[T]) Iter[T]

Shuffle pseudo-randomizes the order of elements of iterator i and returns a new iterator.

func Sort

func Sort[T constraints.Ordered](i Iter[T]) Iter[T]

Sort sorts elements of iterators i, returns a new iterator.

TODO: Sort is not lazy for now.

func SortBy

func SortBy[T any](less func(T, T) bool, i Iter[T]) Iter[T]

SortBy sorts elements of iterators i with function less, returns a new iterator.

TODO: SortBy is not lazy for now.

func StableSortBy

func StableSortBy[T any](less func(T, T) bool, i Iter[T]) Iter[T]

StableSortBy is variant of SortBy, it keeps the original order of equal elements when sorting.

TODO: StableSortBy is not lazy for now.

func StealSlice

func StealSlice[T any](s []T) Iter[T]

func Take

func Take[T any](n int, i Iter[T]) Iter[T]

Take returns the first n elements of iterator, or iterator itself if n > len(s).

⚠️ WARNING: Panic when n < 0.

func TakeWhile

func TakeWhile[T any](f func(T) bool, i Peeker[T]) Iter[T]

TakeWhile returns the longest prefix (possibly empty) of iterator i of elements that satisfy predicate f.

func TypeAssert

func TypeAssert[To, From any](i Iter[From]) Iter[To]

TypeAssert converts a iterator from type From to type To by type assertion.

⚠️ WARNING: Type assertion is not type conversion/casting. See github.com/bytedance/gg/gvalue.TypeAssert for more details.

🚀 EXAMPLE:

ToSlice(TypeAssert[int](FromSlice([]any{1, 2, 3}))) ⏩ []int{1, 2, 3}

func Uniq

func Uniq[T comparable](i Iter[T]) Iter[T]

Uniq returns the distinct elements of iterator. The result is a new iterators contains no duplicate elements.

func UniqBy

func UniqBy[T any, K comparable](f func(T) K, i Iter[T]) Iter[T]

UniqBy distinguishes different elements with key function f, returns the distinct elements of iterator. The result is a new iterators contains no duplicate elements.

func Zip

func Zip[T1, T2, T3 any](f func(T1, T2) T3, a Peeker[T1], b Peeker[T2]) Iter[T3]

Zip applies the function f pairwise on each element of both iterators, Results of f are returned as a new iterator.

If one iterator is shorter than the other, excess elements of the longer iterator are discarded, even if one of the lists is infinite.

type Peeker

type Peeker[T any] interface {
	Iter[T]
	// Peek returns the next N element of iterator without consuming it.
	Peek(n int) []T
}

Peeker is also an iterator interface, which allows users to peek on the elements without consuming them.

Peeker is required by some operations like Equal and Zip. Use ToPeeker to wrap an Iter as a Peeker.

func ToPeeker

func ToPeeker[T any](i Iter[T]) Peeker[T]

ToPeeker wraps Iter as Peeker.

Jump to

Keyboard shortcuts

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