ez

package module
v0.0.0-...-5b8499f Latest Latest
Warning

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

Go to latest
Published: Nov 6, 2024 License: Apache-2.0 Imports: 5 Imported by: 0

README

ez

ez makes it easy to chain together stream operations.

This library declares a Stream interface and implementations for finite, infinite sequences, as well as slices.

Usage

Convert a Seq or a Slice to a Stream

// Create an infinite stream of values
fibonacci := ez.InfiniteStream(func(yield func(int) bool) {
    a := 0
    if !yield(a) {
        return
    }
    b := 1
    for yield(b) {
        a, b = b, b+a
    }
})

// or create a finite stream
oneToTen := ez.FiniteStream(func(yield func(int) bool) {
    for i := range 10 {
        if !yield(i + 1) {
            return
        }
    }
})

// or convert a slice to a stream
sliceStream := ez.SliceStream([]int{1, 2, 3, 4, 5, 6, 7})

// Pipe stream operations together with the `Pipe` function
intStream := ez.Pipe(fibonacci,
    ez.Filter(func(i int) bool { return i > 5 }),
    ez.Map(func(i int) int { return i / 2 }),
    ez.Skip[int](10),
    ez.Take[int](10),
    ez.Reverse[int],
)

// Convert from a stream of one type to another
float64Stream := ez.Convert(intStream, func(i int) float64 {
    return math.Round(math.Sqrt(float64(i)))
})

// Collect values into a slice from a Finite Stream.
values := ez.Collect(float64Stream)

// Concatenate several streams together:
concat := ez.Concat(
    oneToTen,
    sliceStream,
    ez.Pipe(fibonacci, ez.Take[int](10)),
)

// Reduce a stream to a single value
sum := ez.Reduce(concat, 0, func(acc int, v int) int { return acc + v })

Documentation

Overview

Package ez declares a Stream interface and implementations, allowing data stream operations to be applied in a functional style.

Example (Complex)

Example_complex demonstrates complex stream transformations including filtering, mapping, and operations like shuffle, reverse, distinct, sortOrdered, and reduce using a sequence generated from the Fibonacci series.

rng := rand.New(rand.NewChaCha8([32]byte{}))
stream := ez.Convert(
	ez.Pipe(fibonacci,
		ez.Filter(func(i int) bool {
			return i > 5
		}),
		ez.Map(func(i int) int {
			return i / 2
		}),
		ez.Skip[int](10),
		ez.Take[int](10),
		ez.ShuffleWithRand[int](rng),
		ez.Reverse[int],
	), func(i int) float64 {
		return math.Round(math.Sqrt(float64(i)) * math.Sin(float64(i)))
	})
values := ez.Collect(stream)
fmt.Println("m:", values)
sorted := ez.Collect(ez.Pipe(ez.SliceStream(values), ez.Ordered[float64]))
fmt.Println("sorted:", sorted)
distinct := ez.Collect(ez.Pipe(ez.SliceStream(sorted), ez.Distinct[float64]))
fmt.Println("distinct:", distinct)
sum := ez.Reduce(stream, 0, func(a float64, b float64) float64 {
	return a + b
})
fmt.Println("sum:", sum)
Output:

m: [86 -34 -124 86 25 1 190 -26 5 58]
sorted: [-124 -34 -26 1 5 25 58 86 86 190]
distinct: [-124 -34 -26 1 5 25 58 86 190]
sum: 267
Example (Stream)

Example demonstrates the usage of various stream operations such as filtering, mapping, skipping, and taking elements from streams.

package main

import (
	"fmt"
	"github.com/justenwalker/ez"
	"math"
)

// Example Streams
var (
	fibonacci = ez.InfiniteStream(func(yield func(int) bool) {
		a := 0
		if !yield(a) {
			return
		}
		b := 1
		for yield(b) {
			a, b = b, b+a
		}
	})

	oneToTen = ez.FiniteStream(func(yield func(int) bool) {
		for i := range 10 {
			if !yield(i + 1) {
				return
			}
		}
	})
)

func main() {
	// convert a slice to a stream
	sliceStream := ez.SliceStream([]int{1, 2, 3, 4, 5, 6, 7})

	// Pipe stream operations together with the `Pipe` function
	intStream := ez.Pipe(fibonacci,
		ez.Filter(func(i int) bool { return i > 5 }),
		ez.Map(func(i int) int { return i / 2 }),
		ez.Skip[int](10),
		ez.Take[int](10),
		ez.Reverse[int],
	)

	// Convert from a stream of one type to another
	float64Stream := ez.Convert(intStream, func(i int) float64 {
		return math.Round(math.Sqrt(float64(i)))
	})

	// Collect m into a slice from a Finite Stream.
	values := ez.Collect(float64Stream)
	fmt.Println("m:", values)

	// Concatenate several streams together:
	concat := ez.Concat(
		oneToTen,
		sliceStream,
		ez.Pipe(fibonacci, ez.Take[int](10)),
	)

	// Reduce a stream to a single value
	sum := ez.Reduce(concat, 0, func(acc int, v int) int { return acc + v })
	fmt.Println("sum:", sum)
}
Output:

m: [194 152 120 94 74 58 46 36 28 22]
sum: 171
Example (Stream2)

Example demonstrates the usage of various stream operations such as filtering, mapping, skipping, and taking elements from streams.

package main

import (
	"fmt"
	"github.com/justenwalker/ez"
	"math"
)

// Example Streams
var fibonacci = ez.InfiniteStream(func(yield func(int) bool) {
	a := 0
	if !yield(a) {
		return
	}
	b := 1
	for yield(b) {
		a, b = b, b+a
	}
})

func main() {
	zipStream2 := ez.Zip(
		ez.InfiniteStream(func(yield func(int) bool) {
			i := 0
			for {
				if !yield(i) {
					return
				}
				i++
			}
		}),
		fibonacci,
	)

	// Pipe stream operations together with the `Pipe` function
	intStream := ez.Pipe2(zipStream2,
		ez.Filter2(func(l, r int) bool { return r > 5 }),
		ez.Map2(func(l, r int) (int, int) { return l, r * 2 }),
		ez.Skip2[int, int](10),
		ez.Take2[int, int](10),
		ez.Reverse2[int, int],
	)

	// Convert from a stream of one type to another
	float64Stream := ez.Convert2(intStream, func(l, r int) (int, float64) {
		return l, math.Round(math.Sqrt(float64(r)))
	})

	// Collect m into a slice from a Finite Stream.
	leftValues, rightValues := ez.Collect2(float64Stream)
	fmt.Println("left:", leftValues)
	fmt.Println("right:", rightValues)

	// Concatenate several streams together:
	concat := ez.Concat2(
		ez.Pipe2(zipStream2, ez.Take2[int, int](3)),
		ez.Pipe2(zipStream2, ez.Skip2[int, int](3), ez.Take2[int, int](3)),
		ez.Pipe2(zipStream2, ez.Skip2[int, int](6), ez.Take2[int, int](3)),
	)

	// Reduce a stream to a single value
	leftSum := ez.Reduce(ez.Left(concat), 0, func(acc int, v int) int { return acc + v })
	fmt.Println("leftSum:", leftSum)
	rightSum := ez.Reduce(ez.Right(concat), 0, func(acc int, v int) int { return acc + v })
	fmt.Println("rightSum:", rightSum)
}
Output:

left: [25 24 23 22 21 20 19 18 17 16]
right: [387 305 239 188 148 116 91 72 57 44]
leftSum: 36
rightSum: 54

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrInfiniteSequence = errors.New("infinite sequence")

ErrInfiniteSequence indicates that an operation requiring a finite Stream has been given an InfiniteStream. Certain operations like Collect and Reverse only work on Finite streams.

Functions

func AssertFinite

func AssertFinite(stream any)

AssertFinite asserts that the given stream is finite. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Collect

func Collect[D any](stream Stream[D]) []D

Collect returns a slice of all the elements collected from the stream. If the Stream implements `Collect() []D`, that implementation is used. Otherwise, this function collects all elements of the Stream's sequence. If the Stream implements `Size() int`, it can be used to reduce allocations, since the slice can be pre-allocated. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Collect2

func Collect2[L any, R any](stream2 Stream2[L, R]) (left []L, right []R)

func ConvertToMap

func ConvertToMap[K comparable, V any](stream2 Stream2[K, V]) map[K]V

ConvertToMap converts the Stream2 to a Map of L to R values.

func Filter

func Filter[D any](predicate func(v D) bool) func(stream Stream[D]) Stream[D]

Filter returns a new stream with all m for which the predicate returns true.

func Filter2

func Filter2[L, R any](predicate func(l L, r R) bool) func(stream Stream2[L, R]) Stream2[L, R]

Filter2 returns a new stream with all m for which the predicate returns true.

func IsFinite

func IsFinite(stream any) bool

IsFinite checks whether a given Stream is finite by asserting if it implements the Finite interface.

func Map

func Map[D any](mapFn func(v D) D) func(stream Stream[D]) Stream[D]

Map maps m in one stream to m in another stream of the same type.

func Map2

func Map2[L, R any](mapFn func(l L, r R) (L, R)) func(stream2 Stream2[L, R]) Stream2[L, R]

Map2 maps m in one stream to m in another stream of the same type.

func Reduce

func Reduce[D any](stream Stream[D], initial D, accumFunc func(acc D, d D) D) D

Reduce processes elements of a stream sequentially and applies an accumulator function to reduce them to a single value.

func ShuffleWithRand

func ShuffleWithRand[D any](rng *rand.Rand) func(stream Stream[D]) Stream[D]

ShuffleWithRand returns a new Stream with data in a randomized order determined by the given random number generator. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Size

func Size(stream any) int

Size returns the maximum number of elements in the stream, if the stream has a Size method. It returns -1 if the Stream size is unknown; for instance: an InfiniteStream, or FiniteStream with no size.

func Skip

func Skip[D any](n int) func(stream Stream[D]) Stream[D]

Skip returns a new stream with the first n elements skipped.

func Skip2

func Skip2[L any, R any](n int) func(stream2 Stream2[L, R]) Stream2[L, R]

Skip2 returns a new Stream2 with the first n elements skipped.

func Sort

func Sort[D any](cmp func(a, b D) int) func(stream Stream[D]) Stream[D]

Sort returns a new stream with the data elements in sorted order. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Take

func Take[D any](n int) func(stream Stream[D]) Stream[D]

Take returns a new stream which takes at most 'N' elements from the stream. Since take puts an upper bound on the elements returned by the stream, the returned Stream is guaranteed to be Finite.

func Take2

func Take2[L, R any](n int) func(stream2 Stream2[L, R]) Stream2[L, R]

Take2 returns a new Stream2 which takes at most 'N' elements from the stream. Since take puts an upper bound on the elements returned by the stream, the returned Stream2 is guaranteed to be Finite.

Types

type Finite

type Finite interface {
	Finite() bool
}

Finite is a marker interface to detect if a Stream is finite. A Stream must be finite in order for certain operations to be performed such as Collect, or Sort, or Shuffle.

type Stream

type Stream[D any] interface {
	// Seq returns the internal data sequence.
	Seq() iter.Seq[D]
}

Stream represents a generic interface for a stream of values.

func AssumeFinite

func AssumeFinite[D any](stream Stream[D]) Stream[D]

AssumeFinite converts a given Stream into a Finite Stream. The caller guarantees that the stream given is finite. If the stream given is not finite, the behavior is undefined, but likely will result in a program hang/crash. If the given stream is already finite, ie: IsFinite(stream) == true, then this function returns its input unchanged.

func Concat

func Concat[D any](streams ...Stream[D]) Stream[D]

Concat concatenates one or more streams together. If all the Streams given are Finite, the resulting concatenation is also Finite. If all the streams given have Size, then the resulting Stream is Finite, and also has a Size.

func Convert

func Convert[D, R any](stream Stream[D], convertFunc func(v D) R) Stream[R]

Convert converts a stream of type D to a stream of type R using the provided conversion function.

func Distinct

func Distinct[D comparable](stream Stream[D]) Stream[D]

Distinct returns a new stream containing only the distinct elements of the original stream by filtering out duplicates. NOTE: the memory consumed by this stream is unbounded if the Stream is not Finite.

func FiniteStream

func FiniteStream[D any](seq iter.Seq[D]) Stream[D]

FiniteStream returns a Finite Stream backed by the given sequence. The sequence provided is assumed to be finite. If the sequence given is not finite, the behavior is undefined, but likely will result in a program hang/crash.

func FiniteStreamWithSize

func FiniteStreamWithSize[D any](seq iter.Seq[D], size int) Stream[D]

FiniteStreamWithSize returns a Finite Stream backed by the given sequence for which the size is known. The sequence provided is assumed to be finite and have a most number of data elements given. If the sequence given is not finite, the behavior is undefined.

func InfiniteStream

func InfiniteStream[D any](seq iter.Seq[D]) Stream[D]

InfiniteStream returns a new Stream containing an infinite data sequence. This function is used when the underlying sequence does not have a predefined end.

func Left

func Left[L any, R any](stream2 Stream2[L, R]) Stream[L]

Left extracts the left values from the given Stream2 and returns them as a Stream.

func Ordered

func Ordered[D cmp.Ordered](stream Stream[D]) Stream[D]

Ordered sorts Ordered types by their natural order, ascending.

func Pipe

func Pipe[D any](stream Stream[D], pipeFunc ...func(iter Stream[D]) Stream[D]) Stream[D]

Pipe returns a stream after the provided operations have been applied to it in sequence.

func Reverse

func Reverse[D any](stream Stream[D]) Stream[D]

Reverse returns a new stream with the data elements in reverse order. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Right[L any, R any](stream2 Stream2[L, R]) Stream[R]

Right extracts the right values from a given Stream2 and returns them as a Stream.

func Shuffle

func Shuffle[D any](stream Stream[D]) Stream[D]

Shuffle returns a new Stream with data in a randomized order. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func SliceStream

func SliceStream[D any](values []D) Stream[D]

SliceStream returns a Finite Stream backed by the given slice of data elements. Since slices are finite, the stream returned by this function is Finite. Since slices have a known size, the stream returned by this function has Size.

type Stream2

type Stream2[L, R any] interface {
	Seq2() iter.Seq2[L, R]
}

Stream2 represents a generic interface for a stream of tuples.

func AssumeFinite2

func AssumeFinite2[L, R any](stream Stream2[L, R]) Stream2[L, R]

AssumeFinite2 converts a given Stream2 into a Finite Stream2. The caller guarantees that the stream given is finite. If the stream given is not finite, the behavior is undefined, but likely will result in a program hang/crash. If the given stream is already finite, ie: IsFinite(stream) == true, then this function returns its input unchanged.

func Concat2

func Concat2[L, R any](streams ...Stream2[L, R]) Stream2[L, R]

Concat2 concatenates one or more streams together. If all the Streams given are Finite, the resulting concatenation is also Finite. If all the streams given have Size, then the resulting Stream is Finite, and also has a Size.

func Convert2

func Convert2[L1 any, R1 any, L2 any, R2 any](stream2 Stream2[L1, R1], convertFunc func(v1 L1, v2 R1) (L2, R2)) Stream2[L2, R2]

Convert2 converts a Stream2 of one type to a Stream2 of another type using convertFunc.

func FiniteStream2

func FiniteStream2[L any, R any](seq2 iter.Seq2[L, R]) Stream2[L, R]

FiniteStream2 returns a Finite Stream2 backed by the given sequence. The sequence provided is assumed to be finite. If the sequence given is not finite, the behavior is undefined, but likely will result in a program hang/crash.

func FiniteStream2WithSize

func FiniteStream2WithSize[L any, R any](seq2 iter.Seq2[L, R], size int) Stream2[L, R]

FiniteStream2WithSize returns a Finite Stream2 backed by the given sequence for which the size is known. The sequence provided is assumed to be finite and have a most number of data elements given. If the sequence given is not finite, the behavior is undefined.

func InfiniteStream2

func InfiniteStream2[L any, R any](seq2 iter.Seq2[L, R]) Stream2[L, R]

InfiniteStream2 returns a new Stream2 containing an infinite data sequence.

func MapKVStream

func MapKVStream[K comparable, V any](m map[K]V) Stream2[K, V]

MapKVStream converts the given map into a Stream2. NOTE: the stream will produce items in an indeterminate order. For a well-defined ordering, use MapKVStreamOrdered or MapKVStreamSorted.

func MapKVStreamOrdered

func MapKVStreamOrdered[K cmp.Ordered, V any](m map[K]V) Stream2[K, V]

MapKVStreamOrdered converts the given map into a Stream2 using the natural order of the keys.

func MapKVStreamSorted

func MapKVStreamSorted[K comparable, V any](m map[K]V, cmp func(a, b K) int) Stream2[K, V]

MapKVStreamSorted converts the given map into a Stream2 using the provided key ordering.

func Pipe2

func Pipe2[K any, V any](stream Stream2[K, V], pipeFunc ...func(iter Stream2[K, V]) Stream2[K, V]) Stream2[K, V]

Pipe2 returns a Stream2 after the provided operations have been applied to it in sequence.

func Reverse2

func Reverse2[L, R any](stream Stream2[L, R]) Stream2[L, R]

Reverse2 returns a new stream with the data elements in reverse order. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Shuffle2

func Shuffle2[L, R any](stream2 Stream2[L, R]) Stream2[L, R]

Shuffle2 returns a new Stream2 with data in a randomized order. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Shuffle2WithRand

func Shuffle2WithRand[L, R any](rng *rand.Rand, stream2 Stream2[L, R]) Stream2[L, R]

Shuffle2WithRand returns a new Stream2 with data in a randomized order determined by the given random number generator. NOTE: If stream is not finite, this function will panic with ErrInfiniteSequence.

func Swap2

func Swap2[L, R any](stream2 Stream2[L, R]) Stream2[R, L]

Swap2 takes a Stream2 with left and right elements, and returns a new Stream2 with the elements swapped.

func Zip

func Zip[L any, R any](left Stream[L], right Stream[R]) Stream2[L, R]

Zip returns a Stream2 produced by zipping a key and value stream together. If the both streams are infinite, the returns Stream2 is also infinite. If any of the given streams is finite, then a finite Stream2 will be returned having a length of the smallest size between the two streams.

func ZipSliceStream2

func ZipSliceStream2[L any, R any](left []L, right []R) Stream2[L, R]

ZipSliceStream2 converts the given pair of slices into a Stream2 by zipping them together. If the slices provided are not the same length, the stream returned will have the length of the smallest slice provided.

Jump to

Keyboard shortcuts

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