Skip to content

patrickhuber/go-iter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Iteration library in go

This package provides generic iterators and iterator transformations in go.

Iterators defer iteration execution by pushing iteration logic into the Next() function.

This package has a dependency on go-types for the Option[T any] type. Users of the iter module can utilize Result[T] to capture errors or perform transformations on slices that can contain errors.

Looping

Here are three ways to loop over an iterator

A for loop has init, condition and post sections that can be used on an iterator.

rng := iter.Range(0, 10)
for op := rng.Next(); op.IsSome(); op = rng.Next() {
    // code in here
}

Async (calling range on a channel)

You can also loop over a channel created from an Iterator[T] using the iter.Async function. You can specify a context with the iter.WithContext[T] option. If no context is specified, context.Background() is used.

rng := iter.Range(0, 10)
for value := range iter.Async(rng) {
    // code in here
}

Specify a context

rng := iter.Range(0,10)
op := iter.WithContext[int](context.TODO())
for value := range iter.Async(rng, op){
    // code here
}

ForEach uses an anonymous function to iterate over each item to the caller.

rng := iter.Range(0, 10)
iter.ForEach(rng, func(i int) {
    fmt.Print(" ")
    fmt.Print(i)
})
// prints:
//  0 1 2 3 4 5 6 7 8 9

ForEachIndex uses an anonymous function to iterate over each item and the index of that item to the caller.

rng := iter.Range(0, 10)
iter.ForEachIndex(rng, func(index int, i int) {
    if index > 0 {
        fmt.Print(" ")
    }
    fmt.Print(i)
})
// prints:
// 0 1 2 3 4 5 6 7 8 9

The Range function creates an iterator over [begin..end) (inclusive begin, exclusive end)

rng := iter.Range(0, 10)
iter.ForEachIndex(rng, func(index int, i int) {
    if index > 0 {
        fmt.Print(" ")
    }
    fmt.Print(i)
})
// prints:
// 0 1 2 3 4 5 6 7 8 9

The RangeWith function creates an iterator over the range begin..end. The includeBegin and includeEnd flags control if the range is inclusive start and inclusive end.

rng := iter.RangeWith(false, 0, 10, true)
iter.ForEachIndex(rng, func(index int, i int) {
    if index > 0 {
        fmt.Print(" ")
    }
    fmt.Print(i)
})
// prints:
// 1 2 3 4 5 6 7 8 9 10

Repeat returns an iterator that repeats the given element, count times

rep := iter.Repeat(10, 5)
iter.ForEachIndex(rng, func(index int, i int) {
    if index > 0 {
        fmt.Print(" ")
    }
    fmt.Print(i)
})
// prints:
// 10 10 10 10 10

The Select function transforms an iterator of one type to an iterator of another type.

rng := iter.Range(0,10)
strRng := iter.Select(rng, strconv.Itoa)
iter.ForEachIndex(strRng, func(index int, s string){
    if index > 0{
        fmt.Print(" ")
    }
    fmt.Print("'%s'", s)
})
// prints : '0' '1' '2' '3' '4' '5' '6' '7' '8' '9'

The Where function removes items from an iterator using a predicate function.

rng := iter.Range(0,10)
even := func(i int){ return i % 2 == 0}
evens := iter.Where(rng, even)
iter.ForEachIndex(evens, func(index int, i int){
    if index > 0{
        fmt.Print(" ")
    }
    fmt.Print("%d", i)
})
// prints : 0 2 4 6 8

The FromSlice function returns a slice iterator over the given slice

slice := []int{1, 3, 5, 7, 9}
it := iter.FromSlice(slice)
iter.ForEachIndex(it, func(index int, i int){
    if index > 0{
        fmt.Print(" ")
    }
    fmt.Print("%d", i)
})
// prints 1 3 5 7 9

The ToSlice function returns a slice from the given iterator by iterating over all elements.

rng := iter.Range(0, 10)
slice := iter.ToSlice(rng)
fmt.Println(slice)
// prints : [0 1 2 3 4 5 6 7 8 9]

The FromMap function returns an iterator over the given map. FromMap captures keys of the map in the first call to Next(). Subsequent calls to Next() track an index into the key slice to return the next key value pair. Each call to Next() returns an Option tuple of Key Value pairs.

m := map[string]int{"0":0, "1":1, "2":2, "3":3}
it := iter.FromMap(m)
fmt.Print("[ ")
iter.ForEachIndex(it, func(index int, tup types.Tuple2[string, int]){
    if index > 0{
        fmt.Print(", ")
    }    
    k, v := tup.Deconstruct()
    fmt.Print("'%s':%d", k, v)
})
fmt.Print(" ]")
// prints : [ '0':0, '1':1, '2':2, '3':3 ]

The FromMapAsync function returns an iterator over the given map using channels and the supplied context. FromMapAsync uses a go routine to iterate over the map and channels to capture the key value pair. The Next() function removes a tuple key, value from the channel.

m := map[string]int{"0":0, "1":1, "2":2, "3":3}
it := iter.FromMapAsync(m, context.Background())
fmt.Print("[ ")
iter.ForEachIndex(it, func(index int, tup types.Tuple2[string, int]){
    if index > 0{
        fmt.Print(", ")
    }    
    k, v := tup.Deconstruct()
    fmt.Print("'%s':%d", k, v)
})
fmt.Print(" ]")
// prints : [ '0':0, '1':1, '2':2, '3':3 ]

The Count function returns the count of element in the iterator by iterating over all the elements.

expected := 10
rng := iter.Range(0, expected)
actual := iter.Count(rng)
if actual != expected {
    t.Fatalf("expected count of %d but found %d", expected, actual)
}

The FromChannel function returns an iterator over the given channel. A context can be specified in options for early termination.

ch := make(chan int)
go func(c chan int) {
    defer close(c)
    for i := 0; i < 10; i++ {
        ch <- i
    }
}(ch)
it := iter.FromChannel(ch)
iter.ForEach(it, func(i int) {
    fmt.Println(i)
})

First returns the first item in the sequence. If the sequence has no more items, First returns types.None[T]

sequence := iter.Range(15, 30)
first := iter.First(sequence)
switch op := first.(type) {
case types.Some[int]:
    fmt.Println(op.Value)
case types.None[int]:
    fmt.Println("none")
}
// prints 
// 15

FirstWhere returns the first item in the sequence that matches the condition. If the sequence has no more items or no matches exist, First returns types.None[T]

sequence := iter.Range(15, 30)
first := iter.FirstWhere(sequence, func(i int)bool{ return i % 10 == 0})
switch op := first.(type) {
case types.Some[int]:
    fmt.Println(op.Value)
case types.None[int]:
    fmt.Println("none")
}
// prints
// 20

About

a go iterator package

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages