Documentation
¶
Overview ¶
Package itertools provides Iterator type to iteratively access elements of collections/sequences and many functions and methods to works with iterators.
Example (MapFilter) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"strings"
"time"
)
// imitating account name or something
type Account string
// stub representation of financial transaction
type Transaction struct {
From Account
To Account
Amount int
Timestamp time.Time
}
// stub representation of transaction message from message queue
type Message struct {
FromTo string
Amount int
Time string
}
func messageToTransaction(msg Message) Transaction {
var tx Transaction
parts := strings.SplitN(msg.FromTo, "---", 2)
tx.From, tx.To = Account(parts[0]), Account(parts[1])
tx.Amount = msg.Amount
tx.Timestamp, _ = time.Parse(time.RFC3339Nano, msg.Time)
return tx
}
// mock fraud checker for financial transactions
type FraudChecker struct {
definitelyFraudulent Account
}
func (fc *FraudChecker) IsFraudulentTransaction(tx Transaction) bool {
return tx.To == fc.definitelyFraudulent || tx.From == fc.definitelyFraudulent
}
// mock fraud transaction alerter
type Alerter struct{}
func (Alerter) Alert(tx Transaction) {
var sb strings.Builder
sb.WriteString("!!!FOUND FRAUD TRANSACTION!!!\n")
sb.WriteString(fmt.Sprintf("From: %q\n", tx.From))
sb.WriteString(fmt.Sprintf("To: %q\n", tx.To))
sb.WriteString(fmt.Sprintf("Amount: %d\n", tx.Amount))
fmt.Println(sb.String())
}
// mock consumer of message queue/broker
type MessageConsumer []Message
// imitating process of message consumption
func (mc *MessageConsumer) StartConsume() <-chan Message {
messages := make([]Message, len(*mc))
copy(messages, *mc)
ch := make(chan Message)
go func() {
for _, msg := range messages {
ch <- msg
}
close(ch)
}()
return ch
}
func main() {
const fraud = "1"
consumer := MessageConsumer{
{
FromTo: "2---3",
Amount: 15,
Time: time.Now().Format(time.RFC3339Nano),
},
{
FromTo: "3---1",
Amount: 15,
Time: time.Now().Format(time.RFC3339Nano),
},
{
FromTo: "5---6",
Amount: 13,
Time: time.Now().Format(time.RFC3339Nano),
},
{
FromTo: "7---8",
Amount: 5,
Time: time.Now().Format(time.RFC3339Nano),
},
{
FromTo: "4---1",
Amount: 10,
Time: time.Now().Format(time.RFC3339Nano),
},
{
FromTo: "1---0",
Amount: 25,
Time: time.Now().Format(time.RFC3339Nano),
},
}
ch := consumer.StartConsume()
fraudChecker := FraudChecker{definitelyFraudulent: fraud}
alerter := Alerter{}
iter := itertools.Map(
// iterating over messages
itertools.NewChanIterator(ch),
// mapping them to transactions
messageToTransaction,
// keeping only fraudulent ones
).Filter(fraudChecker.IsFraudulentTransaction)
iter.Range(func(tx Transaction) bool {
alerter.Alert(tx)
return true
})
}
Output: !!!FOUND FRAUD TRANSACTION!!! From: "3" To: "1" Amount: 15 !!!FOUND FRAUD TRANSACTION!!! From: "4" To: "1" Amount: 10 !!!FOUND FRAUD TRANSACTION!!! From: "1" To: "0" Amount: 25
Example (MapReduce) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"math"
)
func main() {
data := []int{6, 10, 7, 12, 6, 14, 8, 13, 10, 14}
sum := itertools.Sum(itertools.NewSliceIterator(data))
avg := float64(sum) / float64(len(data))
stddev := itertools.
Map(
// iterating over data
itertools.NewSliceIterator(data),
// transforming data from int to float64
func(n int) float64 { return float64(n) },
).
// calculating standard deviation of data
Reduce(0, func(acc float64, elem float64) float64 {
return acc + (elem-avg)*(elem-avg)
})
stddev = math.Sqrt(stddev / float64(len(data)-1))
fmt.Println("data:", data)
fmt.Printf("standard deviation: %.2f", stddev)
}
Output: data: [6 10 7 12 6 14 8 13 10 14] standard deviation: 3.16
Example (Set) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"sync"
"time"
)
func main() {
values := map[int]struct{}{}
for i := 0; i < 1_000_000; i++ {
values[i%40000] = struct{}{}
}
const batchSize = 2500
iter := itertools.
// batching incoming values into batches with size batchSize (2500)
Batched(itertools.NewMapKeysIterator(values).
// keeping only numbers divisible by 4
Filter(func(n int) bool { return n%4 == 0 }),
batchSize)
var wg sync.WaitGroup
for iter.Next() {
batch := iter.Elem()
wg.Add(1)
go func() {
defer wg.Done()
process(batch)
}()
}
wg.Wait()
}
func process(values []int) {
// long processing imitation
time.Sleep(time.Duration(len(values)) * time.Microsecond)
fmt.Printf("processed %d items\n", len(values))
}
Output: processed 2500 items processed 2500 items processed 2500 items processed 2500 items
Index ¶
- func Find[T any](i *Iterator[T], f func(T) bool) (T, bool)
- func Max[T cmp.Ordered](i *Iterator[T]) T
- func Min[T cmp.Ordered](i *Iterator[T]) T
- func Sum[T Summable](i *Iterator[T]) T
- type AllocationOption
- type Enumeration
- type Iterator
- func Batched[T any](i *Iterator[T], batchSize int) *Iterator[[]T]
- func Chain[T any](iters ...*Iterator[T]) *Iterator[T]
- func Cycle[T any](i *Iterator[T], opts ...AllocationOption) *Iterator[T]
- func Enumerate[T any](i *Iterator[T]) *Iterator[Enumeration[T]]
- func Map[T, U any](i *Iterator[T], mapper func(T) U) *Iterator[U]
- func New[T any](f func() (T, bool)) *Iterator[T]
- func NewAsciiIterator(s string) *Iterator[byte]
- func NewChanIterator[T any](ch <-chan T) *Iterator[T]
- func NewMapIterator[K comparable, V any](m map[K]V) *Iterator[Pair[K, V]]
- func NewMapKeysIterator[K comparable, V any](m map[K]V) *Iterator[K]
- func NewMapValuesIterator[K comparable, V any](m map[K]V) *Iterator[V]
- func NewSliceIterator[S ~[]T, T any](s S) *Iterator[T]
- func NewUTF8Iterator(s string) *Iterator[rune]
- func Repeat[T any](elem T) *Iterator[T]
- func Zip[T, U any](t *Iterator[T], u *Iterator[U]) *Iterator[Pair[T, U]]
- func (i *Iterator[T]) All(f func(T) bool) bool
- func (i *Iterator[T]) Any(f func(T) bool) bool
- func (i *Iterator[T]) Collect(opts ...AllocationOption) []T
- func (i *Iterator[T]) Count() int
- func (i *Iterator[T]) Drop(n int) int
- func (i *Iterator[T]) Elem() T
- func (i *Iterator[T]) Filter(f func(T) bool) *Iterator[T]
- func (i *Iterator[T]) Limit(size int) *Iterator[T]
- func (i *Iterator[T]) Max(f func(T, T) int) T
- func (i *Iterator[T]) Next() bool
- func (i *Iterator[T]) Range(f func(T) bool)
- func (i *Iterator[T]) Reduce(acc T, f func(acc T, elem T) T) T
- func (i *Iterator[T]) WithStep(step int) *Iterator[T]
- type Pair
- type Summable
Examples ¶
- Package (MapFilter)
- Package (MapReduce)
- Package (Set)
- Batched
- Chain
- Cycle
- Enumerate
- Find (Found)
- Find (Not_found)
- Iterator.All (False)
- Iterator.All (True)
- Iterator.Any (False)
- Iterator.Any (True)
- Iterator.Collect
- Iterator.Count
- Iterator.Drop
- Iterator.Filter
- Iterator.Limit
- Iterator.Max
- Iterator.Range
- Iterator.Range (Conditional_stop)
- Iterator.Reduce
- Iterator.WithStep
- Map
- Max
- Min
- New
- NewAsciiIterator
- NewChanIterator
- NewMapIterator
- NewSliceIterator
- NewUTF8Iterator
- Repeat
- Zip
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Find ¶
Find applies function f to elements of iterator, returning first element for which the function returned true. The returned boolean value shows if the element was found (i.e. is valid). If no element was found, Find returns false as second returned value.
Example (Found) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
type Person struct {
Name string
Age uint
}
people := []Person{
{"Bob", 31},
{"John", 42},
{"Michael", 17},
{"Jenny", 26},
}
target := "Michael"
iter := itertools.NewSliceIterator(people)
person, found := itertools.Find(iter, func(person Person) bool {
return person.Name == target
})
if found {
fmt.Printf("Found person with name %q. Age: %d\n", person.Name, person.Age)
} else {
fmt.Printf("Failed to find person with name %q\n", target)
}
}
Output: Found person with name "Michael". Age: 17
Example (Not_found) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
type Person struct {
Name string
Age uint
}
people := []Person{
{"Bob", 31},
{"John", 42},
{"Michael", 17},
{"Jenny", 26},
}
target := "Mike"
iter := itertools.NewSliceIterator(people)
person, found := itertools.Find(iter, func(person Person) bool {
return person.Name == target
})
if found {
fmt.Printf("Found person with name %q. Age: %d\n", person.Name, person.Age)
} else {
fmt.Printf("Failed to find person with name %q\n", target)
}
}
Output: Failed to find person with name "Mike"
func Max ¶
Max return max value of iterator.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{-80, 23, 0, 54, 13, -39, 45, 33}
iter := itertools.NewSliceIterator(s)
fmt.Println("Max value:", itertools.Max(iter))
}
Output: Max value: 54
Types ¶
type AllocationOption ¶
type AllocationOption func(options *allocOptions)
AllocationOption allows to manipulate allocations in iteration methods/functions.
func WithPrealloc ¶
func WithPrealloc(prealloc int) AllocationOption
WithPrealloc sets preallocation size (capacity) for allocated buffers/slices.
type Enumeration ¶
Enumeration is a specific case of Pair for Enumerate function.
func (Enumeration[T]) Unpack ¶
func (p Enumeration[T]) Unpack() (T, int)
Unpack returns values of Enumeration as tuple.
type Iterator ¶
type Iterator[T any] struct { // contains filtered or unexported fields }
Iterator is used to process all elements of some collection or sequence. Iterator contains methods to access the elements and to process or aggregate them in many ways.
func Batched ¶
Batched creates new iterator that returns slices of T (aka batch) with size up to batchSize, using given source iterator.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
iter := itertools.Batched(itertools.NewSliceIterator(s), 2)
for iter.Next() {
fmt.Println("got batch:", iter.Elem())
}
}
Output: got batch: [1 2] got batch: [3 4] got batch: [5 6] got batch: [7 8] got batch: [9]
func Chain ¶
Chain chains iterators, returning resulting chained iterator. The result iterator yields elements of the first iterator, then elements of the second one etc.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
iter1 := itertools.NewSliceIterator([]byte("Hello"))
ch := make(chan byte)
go func() {
ch <- ' '
close(ch)
}()
iter2 := itertools.NewChanIterator(ch)
iter3 := itertools.NewAsciiIterator("World!")
chainedIter := itertools.Chain(iter1, iter2, iter3)
fmt.Println("chained collected result:", string(chainedIter.Collect()))
}
Output: chained collected result: Hello World!
func Cycle ¶
func Cycle[T any](i *Iterator[T], opts ...AllocationOption) *Iterator[T]
Cycle creates new iterator that endlessly repeats elements of source iterator. If source iterator is empty, the cycle iterator is also empty.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{1, 2, 3}
iter := itertools.Cycle(itertools.NewSliceIterator(s))
for i := 0; i < 10; i++ {
iter.Next()
fmt.Println(iter.Elem())
}
}
Output: 1 2 3 1 2 3 1 2 3 1
func Enumerate ¶
func Enumerate[T any](i *Iterator[T]) *Iterator[Enumeration[T]]
Enumerate creates new iterator that returns Enumeration contating current element of source iterator along with current iteration count (starting from 0).
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
type Person struct {
Name string
Age uint
}
people := []Person{
{"Bob", 31},
{"John", 42},
{"Michael", 17},
{"Jenny", 26},
}
iter := itertools.Enumerate(itertools.NewSliceIterator(people))
for iter.Next() {
person, i := iter.Elem().Unpack()
fmt.Printf("Index: %d ||| Name: %s ||| Age: %d\n", i, person.Name, person.Age)
}
}
Output: Index: 0 ||| Name: Bob ||| Age: 31 Index: 1 ||| Name: John ||| Age: 42 Index: 2 ||| Name: Michael ||| Age: 17 Index: 3 ||| Name: Jenny ||| Age: 26
func Map ¶
Map returns new iterator that yields elements of type U by calling mapper to each element of type T of source iterator.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"math"
)
func main() {
const maxPoints = 150
results := []int{25, 100, 95, 36, 145, 67, 49, 123}
percentageIter := itertools.Map(
itertools.NewSliceIterator(results),
func(result int) int {
return int(math.Round(float64(result) / maxPoints * 100))
},
)
fmt.Println("Results percentage:", percentageIter.Collect())
}
Output: Results percentage: [17 67 63 24 97 45 33 82]
func New ¶
New creates new Iterator using given iteration function. Function returns an element of collection and boolean value indicating if the element is valid (i.e. false means that the iteration is over).
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
arr := [5]int{5, 10, 15, 20, 25}
var idx int
// function to manually iterator over slice.
// It is more comfortable to use itertools.NewSliceIterator in this case
f := func() (int, bool) {
if idx >= len(arr) {
return 0, false
}
elem := arr[idx]
idx++
return elem, true
}
iter := itertools.New(f)
fmt.Println(iter.Next(), iter.Elem())
fmt.Println(iter.Next(), iter.Elem())
fmt.Println(iter.Next(), iter.Elem())
fmt.Println(iter.Next(), iter.Elem())
fmt.Println(iter.Next(), iter.Elem())
fmt.Println(iter.Next())
}
Output: true 5 true 10 true 15 true 20 true 25 false
func NewAsciiIterator ¶
NewAsciiIterator creates iterator yielding bytes from string (interpreting string as []byte).
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"unicode"
)
func main() {
s := "Hello, World!"
iter := itertools.NewAsciiIterator(s)
iter = iter.Filter(func(b byte) bool {
return unicode.IsPunct(rune(b))
})
fmt.Println("phrase punctuation signs:", string(iter.Collect()))
}
Output: phrase punctuation signs: ,!
func NewChanIterator ¶
NewChanIterator creates iterator yielding values from channel until the channel is closed.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"slices"
"sync"
)
func main() {
ch := make(chan int)
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for j := 0; j < 5; j++ {
ch <- j
}
}()
}
go func() {
wg.Wait()
close(ch)
}()
iter := itertools.NewChanIterator(ch)
result := iter.Collect()
slices.Sort(result)
fmt.Println(result)
}
Output: [0 0 0 1 1 1 2 2 2 3 3 3 4 4 4]
func NewMapIterator ¶
func NewMapIterator[K comparable, V any](m map[K]V) *Iterator[Pair[K, V]]
NewMapIterator creates iterator yielding key-value pairs from map. NewMapIterator uses reflect package to keep iteration state.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"slices"
)
func main() {
months := map[int]string{
1: "January",
2: "February",
3: "March",
4: "April",
5: "May",
6: "June",
7: "July",
8: "August",
9: "September",
10: "October",
11: "November",
12: "December",
}
iter := itertools.NewMapIterator(months)
summerMonths := []string{"June", "July", "August"}
iter = iter.Filter(func(p itertools.Pair[int, string]) bool {
return slices.Contains(summerMonths, p.Second)
})
// iterating over map keys (months numbers) rather than entire key-value pairs
numbersIter := itertools.Map(iter, func(p itertools.Pair[int, string]) int {
return p.First
})
summerMonthsNumbers := numbersIter.Collect()
slices.Sort(summerMonthsNumbers)
fmt.Println("summer months numbers:", summerMonthsNumbers)
}
Output: summer months numbers: [6 7 8]
func NewMapKeysIterator ¶
func NewMapKeysIterator[K comparable, V any](m map[K]V) *Iterator[K]
NewMapKeysIterator creates iterator yielding keys from map. NewMapKeysIterator uses reflect package to keep iteration state.
func NewMapValuesIterator ¶
func NewMapValuesIterator[K comparable, V any](m map[K]V) *Iterator[V]
NewMapValuesIterator creates iterator yielding values from map. NewMapValuesIterator uses reflect package to keep iteration state.
func NewSliceIterator ¶
NewSliceIterator creates iterator for given slice, meaning iterator will yield all elements of the slice.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{1, 2, 3, 4, 5}
iter := itertools.NewSliceIterator(s)
for iter.Next() {
fmt.Println(iter.Elem())
}
fmt.Println("is finished:", !iter.Next())
}
Output: 1 2 3 4 5 is finished: true
func NewUTF8Iterator ¶
NewUTF8Iterator creates iterator yielding runes from string (interpreting string as []rune)
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
"unicode"
)
func main() {
s := "Hello, 世界"
iter := itertools.NewUTF8Iterator(s)
iter = iter.Filter(func(r rune) bool {
return unicode.Is(unicode.Han, r)
})
fmt.Println("chinese hieroglyphs:", string(iter.Collect()))
}
Output: chinese hieroglyphs: 世界
func Repeat ¶
Repeat creates new iterator that endlessly yields elem.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
iter := itertools.Repeat("HELLO")
for i := 0; i < 5; i++ {
iter.Next()
fmt.Println(iter.Elem())
}
}
Output: HELLO HELLO HELLO HELLO HELLO
func Zip ¶
Zip joins two iterators into a one yielding Pair of the iterators' elements. Returned iterator yields Pairs until one of source iterators is empty.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
names := []string{"Bob", "John", "Michael", "Jenny"}
ages := []uint{31, 42, 17, 26}
nameIter := itertools.NewSliceIterator(names)
ageIter := itertools.NewSliceIterator(ages)
iter := itertools.Zip(nameIter, ageIter)
for iter.Next() {
name, age := iter.Elem().Unpack()
fmt.Printf("Name: %s ::: Age: %d\n", name, age)
}
}
Output: Name: Bob ::: Age: 31 Name: John ::: Age: 42 Name: Michael ::: Age: 17 Name: Jenny ::: Age: 26
func (*Iterator[T]) All ¶
All applies function f to every element of iterator. If f returns true for all elements of iterator, All returns true. Otherwise, All returns false. All is lazy and will stop iterating after first element for which f returns false. All returns true for empty iterator.
Example (False) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{-4, -3, -2, -1, 0, 1, 2, 3, 4}
predicate := func(n int) bool {
return n < 2
}
iter := itertools.NewSliceIterator(s)
fmt.Println(iter.All(predicate))
}
Output: false
Example (True) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{-4, -3, -2, -1, 0, 1, 2, 3, 4}
predicate := func(n int) bool {
if n < 0 {
n = -n
}
return n < 5
}
iter := itertools.NewSliceIterator(s)
fmt.Println(iter.All(predicate))
}
Output: true
func (*Iterator[T]) Any ¶
Any applies function f to every element of iterator. If f returns false for all elements of iterator, Any returns false. Otherwise, Any return true. Any is lazy and will stop iterating after first element for which f returns true. Any returns false for empty iterator.
Example (False) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{-4, -3, -2, -1, 0, 1, 2, 3, 4}
predicate := func(n int) bool {
if n < 0 {
n = -n
}
return n >= 5
}
iter := itertools.NewSliceIterator(s)
fmt.Println(iter.Any(predicate))
}
Output: false
Example (True) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{-4, -3, -2, -1, 0, 1, 2, 3, 4}
predicate := func(n int) bool {
return n < 2
}
iter := itertools.NewSliceIterator(s)
fmt.Println(iter.Any(predicate))
}
Output: true
func (*Iterator[T]) Collect ¶
func (i *Iterator[T]) Collect(opts ...AllocationOption) []T
Collect returns all elements of iterator as slice.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []string{"First", "Second", "Third"}
idx := len(s) - 1
// function to iterate over slice in reverse order
f := func() (string, bool) {
if idx < 0 {
return "", false
}
elem := s[idx]
idx--
return elem, true
}
iter := itertools.New(f)
fmt.Println(iter.Collect())
}
Output: [Third Second First]
func (*Iterator[T]) Count ¶
Count returns amount of remaining elements in iterator. Call of Count consumes all elements.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{1, 2, 3, 4}
iter := itertools.NewSliceIterator(s)
fmt.Println(iter.Count())
}
Output: 4
func (*Iterator[T]) Drop ¶
Drop skips next n elements in iterator, returning amount of skipped elements (if iterator has fewer elements than n, returned value is equal to the amount of elements).
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
const skipNextTwo = 0x01
data := []byte{'H', 'e', 'l', 'l', 'o', 0x01, 'W', 'o', 'r', 'l', 'd'}
iter := itertools.NewSliceIterator(data)
for iter.Next() {
elem := iter.Elem()
if elem == skipNextTwo {
dropped := iter.Drop(2)
fmt.Printf("dropped %d elements\n", dropped)
} else {
fmt.Printf("%c\n", elem)
}
}
}
Output: H e l l o dropped 2 elements r l d
func (*Iterator[T]) Elem ¶
func (i *Iterator[T]) Elem() T
Elem returns the current element of iterator. If iterator is empty (Next returns false), result is unspecified.
func (*Iterator[T]) Filter ¶
Filter produces new iterator that yields only elements for which function f returns true.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{1, 2, 3, 4, 5, 6, 7}
oddFilter := func(n int) bool {
return n%2 == 1
}
evenFilter := func(n int) bool {
return n%2 == 0
}
oddIter := itertools.NewSliceIterator(s).Filter(oddFilter)
evenIter := itertools.NewSliceIterator(s).Filter(evenFilter)
fmt.Println(oddIter.Collect())
fmt.Println(evenIter.Collect())
}
Output: [1 3 5 7] [2 4 6]
func (*Iterator[T]) Limit ¶
Limit produces new iterator that can return at most size elements.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
iter := itertools.NewAsciiIterator("Hello World!").Limit(5)
for iter.Next() {
fmt.Printf("%c\n", iter.Elem())
}
}
Output: H e l l o
func (*Iterator[T]) Max ¶
Max returns max element of iterator, using provided comparison function. Comparison function returns next results:
- -1: if the first argument is less than second one
- 0: if two arguments are equal
- 1: if the first argument is greater than second one
Example ¶
package main
import (
"cmp"
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
type Person struct {
Name string
Age uint
}
people := []Person{
{"Bob", 31},
{"John", 42},
{"Michael", 17},
{"Jenny", 26},
}
iter := itertools.NewSliceIterator(people)
oldest := iter.Max(func(a Person, b Person) int {
return cmp.Compare(a.Age, b.Age)
})
fmt.Printf("Oldest person: %s (age %d)\n", oldest.Name, oldest.Age)
}
Output: Oldest person: John (age 42)
func (*Iterator[T]) Next ¶
Next proceeds iterator to the next element, returning boolean value to show that said element exists.
func (*Iterator[T]) Range ¶
Range calls function f for every element of iterator until the function returns false
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []string{"First", "Second", "Third", "Fourth", "Fifth"}
iter := itertools.NewSliceIterator(s)
iter.Range(func(s string) bool {
fmt.Println(s)
return true
})
}
Output: First Second Third Fourth Fifth
Example (Conditional_stop) ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{5, 4, 2, 0, -1, -8, -16}
iter := itertools.NewSliceIterator(s)
iter.Range(func(n int) bool {
fmt.Println(n)
if n < 0 {
return false
}
return true
})
}
Output: 5 4 2 0 -1
func (*Iterator[T]) Reduce ¶
func (i *Iterator[T]) Reduce(acc T, f func(acc T, elem T) T) T
Reduce applies given function f to every element of iterator, using previous accumulating state and returning updated accumulating state on each iteration. Reduce also accepts initial value for accumulating state. Reduce returns final accumulating state created after applying f to all elements of iterator.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sum := func(acc int, n int) int {
return acc + n
}
iter := itertools.NewSliceIterator(s)
fmt.Println("Sum of slice:", iter.Reduce(0, sum))
}
Output: Sum of slice: 55
func (*Iterator[T]) WithStep ¶
WithStep produces new iterator that yields every "step"th element of underlying iterator If step is non-positive, returns empty iterator.
Example ¶
package main
import (
"fmt"
"github.com/KSpaceer/itertools"
)
func main() {
s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
iter := itertools.NewSliceIterator(s).WithStep(2)
for iter.Next() {
fmt.Println(iter.Elem())
}
}
Output: 1 3 5 7 9
type Pair ¶
type Pair[T, U any] struct { First T Second U }
Pair is 2-size tuple of heterogeneous values.
type Summable ¶
type Summable interface {
constraints.Integer | constraints.Float | constraints.Complex | ~string
}