Skip to main content

seq2

import "github.com/go-softwarelab/common/pkg/seq2"

Package seq2 provides a comprehensive set of utilities for working with key-value sequences in Go applications.

The goal of this package is to offer a rich set of functions for creating, transforming, and consuming iter.Seq2, enabling developers to work with collections of key-value pairs in a functional programming style. The package includes utilities for filtering, mapping, reducing, and sorting sequences, as well as combining and partitioning them.

The package is designed to reduce boilerplate code and improve readability by providing a consistent API for common sequence operations. It leverages Go's type safety and generics to ensure that operations on sequences are both flexible and safe. The Sequence struct is worth mentioning explicitly, allowing method chaining and fluent composition of sequence operations.

Append

func Append[K any, V any](seq iter.Seq2[K, V], key K, value V) iter.Seq2[K, V]

Append appends element to the end of a sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2})
input = seq2.SortByKeys(input)

// Append a new key-value pair to the sequence
appended := seq2.Append(input, "c", 3)

result := seq2.CollectToMap(appended)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

Collect

func Collect[K comparable, V any](seq iter.Seq2[K, V]) []types.Pair[K, V]

Collect collects the elements of the given sequence into a slice of types.Pair of K and V.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

result := seq2.Collect(input)

fmt.Println(result)

}

Output

[{a 1} {b 2} {c 3}]

CollectToMap

func CollectToMap[K comparable, V any](seq iter.Seq2[K, V]) map[K]V

CollectToMap collects the elements of the given sequence into a map.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

result := seq2.CollectToMap(input)

fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

Concat

func Concat[K any, V any](sequences ...iter.Seq2[K, V]) iter.Seq2[K, V]

Concat concatenates multiple sequences into a single sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
first := seq2.FromMap(map[string]int{"a": 1, "b": 2})
first = seq2.SortByKeys(first)
second := seq2.FromMap(map[string]int{"c": 3, "d": 4})
second = seq2.SortByKeys(second)

// Concatenate two sequences
combined := seq2.Concat(first, second)

result := seq2.CollectToMap(combined)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3 d:4]

Contains

func Contains[K comparable, V any](seq iter.Seq2[K, V], key K) bool

Contains returns true if the key is in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

contains := seq2.Contains(input, "b")

fmt.Println(contains)
}

Output

true

ContainsAll

func ContainsAll[K comparable, V any](seq iter.Seq2[K, V], keys ...K) bool

ContainsAll returns true if all keys are in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

containsAll := seq2.ContainsAll(input, "a", "c", "d")

fmt.Println(containsAll)
}

Output

true

ContainsAllValues

func ContainsAllValues[K any, V comparable](seq iter.Seq2[K, V], values ...V) bool

ContainsAllValues returns true if all values are in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

containsAllValues := seq2.ContainsAllValues(input, 1, 3)

fmt.Println(containsAllValues)
}

Output

true

ContainsPair

func ContainsPair[K comparable, V comparable](seq iter.Seq2[K, V], key K, value V) bool

ContainsPair returns true if the key-value pair is in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

containsPair := seq2.ContainsPair(input, "b", 2)

fmt.Println(containsPair)
}

Output

true

ContainsValue

func ContainsValue[K any, V comparable](seq iter.Seq2[K, V], value V) bool

ContainsValue returns true if the value is in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

containsValue := seq2.ContainsValue(input, 3)

fmt.Println(containsValue)
}

Output

true

Count

func Count[K any, V any](seq iter.Seq2[K, V]) int

Count returns the number of elements in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Count returns the number of elements in the sequence
count := seq2.Count(input)

fmt.Println(count)
}

Output

3

Cycle

func Cycle[K, V any](seq iter.Seq2[K, V]) iter.Seq2[K, V]

Cycle repeats the sequence indefinitely.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2})
input = seq2.SortByKeys(input)

// Create an infinite cycle of the sequence
cycled := seq2.Cycle(input)

// Take only the first 5 elements from the infinite cycle
limited := seq2.Take(cycled, 5)

seq2.ForEach(limited, func(k string, v int) {
fmt.Println(k, v)
})

}

Output

a 1
b 2
a 1
b 2
a 1

CycleTimes

func CycleTimes[K, V any](seq iter.Seq2[K, V], count int) iter.Seq2[K, V]

CycleTimes repeats the sequence count times.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2})
input = seq2.SortByKeys(input)

// Repeat the sequence 2 times
cycled := seq2.CycleTimes(input, 2)

seq2.ForEach(cycled, func(k string, v int) {
fmt.Println(k, v)
})

}

Output

a 1
b 2
a 1
b 2

Distinct

func Distinct[K comparable, V comparable](seq iter.Seq2[K, V]) iter.Seq2[K, V]

Distinct returns a new sequence that contains only the unique elements of the given sequence. SQL-like alias for Uniq.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence with duplicate key-value pairs
input := seq2.Concat(
seq2.FromMap(map[string]int{"a": 1, "b": 2}),
seq2.FromMap(map[string]int{"a": 1, "c": 3}),
)

// Distinct is an alias for Uniq
unique := seq2.Distinct(input)

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

DistinctKeys

func DistinctKeys[K comparable, V any](seq iter.Seq2[K, V]) iter.Seq2[K, V]

DistinctKeys returns a new sequence that contains only the unique keys of the given sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence with duplicate keys
input := seq2.Concat(
seq2.FromMap(map[string]int{"a": 1, "b": 2}),
seq2.FromMap(map[string]int{"a": 3, "c": 4}),
)

// DistinctKeys is an alias for UniqKeys
unique := seq2.DistinctKeys(input)

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[a:1 b:2 c:4]

Each

func Each[K any, V any](seq iter.Seq2[K, V], consumer Consumer[K, V]) iter.Seq2[K, V]

Each returns a sequence that applies the given consumer to each element of the input sequence and pass it further. Each is an alias for Tap. Comparing to ForEach, this is a lazy function and doesn't consume the input sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

tapped := seq2.Each(input, func(k string, v int) {
fmt.Printf("Each: %s -> %d\n", k, v)
})

seq2.Flush(tapped)

}

Output

Each: a -> 1
Each: b -> 2
Each: c -> 3

Empty

func Empty[K, V any]() iter.Seq2[K, V]

Empty returns an empty sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create an empty sequence
empty := seq2.Empty[any, any]()

seq2.ForEach(empty, func(any, any) {
fmt.Println("Should not be called")
})
}

Output

Every

func Every[K, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) bool

Every returns true if all elements satisfy the predicate.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 2, "b": 4, "c": 6, "d": 8})
input = seq2.SortByKeys(input)

every := seq2.Every(input, func(k string, v int) bool {
return v%2 == 0
})

fmt.Println(every)
}

Output

true

Exists

func Exists[K, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) bool

Exists returns true if there is at least one element that satisfies the predicate.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

exists := seq2.Exists(input, func(k string, v int) bool {
return k > "c" && v > 3
})

fmt.Println(exists)
}

Output

true

Filter

func Filter[K any, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) iter.Seq2[K, V]

Filter returns a new sequence that contains only the elements that satisfy the predicate.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

// Filter elements where the value is even
filtered := seq2.Filter(input, func(k string, v int) bool {
return v%2 == 0
})

result := seq2.CollectToMap(filtered)
fmt.Println(result)
}

Output

map[b:2 d:4]

FilterByKey

func FilterByKey[K any, V any](seq iter.Seq2[K, V], predicate KeyPredicate[K]) iter.Seq2[K, V]

FilterByKey returns a new sequence that contains only the elements that satisfy the predicate.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

// Filter elements by key
filtered := seq2.FilterByKey(input, func(k string) bool {
return k > "b"
})

result := seq2.CollectToMap(filtered)
fmt.Println(result)
}

Output

map[c:3 d:4]

FilterByValue

func FilterByValue[K any, V any](seq iter.Seq2[K, V], predicate ValuePredicate[V]) iter.Seq2[K, V]

FilterByValue returns a new sequence that contains only the elements that satisfy the predicate.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

// Filter elements by value
filtered := seq2.FilterByValue(input, func(v int) bool {
return v <= 2
})

result := seq2.CollectToMap(filtered)
fmt.Println(result)
}

Output

map[a:1 b:2]

FindAll

func FindAll[K, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) iter.Seq2[K, V]

FindAll returns all elements that satisfy the predicate.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

found := seq2.FindAll(input, func(k string, v int) bool {
return v > 2
})

result := seq2.CollectToMap(found)
fmt.Println(result)
}

Output

map[c:3 d:4]

Flush

func Flush[K any, V any](seq iter.Seq2[K, V])

Flush consumes all elements of the input sequence.

Example
package main

import (
"fmt"
"iter"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence that has side effects when consumed
sideEffects := iter.Seq2[string, int](func(yield func(string, int) bool) {
fmt.Println("First element consumed")
if !yield("a", 1) {
return
}
fmt.Println("Second element consumed")
if !yield("b", 2) {
return
}
fmt.Println("Third element consumed")
if !yield("c", 3) {
return
}
})

// Flush consumes all elements without doing anything with them
seq2.Flush(sideEffects)

}

Output

First element consumed
Second element consumed
Third element consumed

ForEach

func ForEach[K any, V any](seq iter.Seq2[K, V], consumer Consumer[K, V])

ForEach applies consumer to each element of the input sequence. Comparing to Each, this is not a lazy function and consumes the input sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed("a", "b", "c")

// ForEach consumes the sequence and applies the function
seq2.ForEach(input, func(k int, v string) {
fmt.Printf("%d: %s\n", k, v)
})

}

Output

0: a
1: b
2: c

FromMap

func FromMap[Map ~map[K]V, K comparable, V any](m Map) iter.Seq2[K, V]

FromMap creates a new iter.Seq2 from the given map.

FromSlice

func FromSlice[Slice ~[]E, E any](slice Slice) iter.Seq2[int, E]

FromSlice creates a new sequence from the given slice with index as keys.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence from a slice
slice := []string{"a", "b", "c"}
sequence := seq2.FromSlice(slice)

result := seq2.CollectToMap(sequence)
fmt.Println(result)
}

Output

map[0:a 1:b 2:c]

Get

func Get[K comparable, V any](seq iter.Seq2[K, V], key K) optional.Value[V]

Get returns the element at the specified key.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

value := seq2.Get(input, "c")

fmt.Println(value.MustGet())
}

Output

3

IsEmpty

func IsEmpty[K, V any](seq iter.Seq2[K, V]) bool

IsEmpty returns true if the sequence is empty.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
emptySeq := seq2.Empty[any, any]()

nonEmptySeq := seq2.OfIndexed("a")

fmt.Printf("Empty sequence: %v\n", seq2.IsEmpty(emptySeq))
fmt.Printf("Non-empty sequence: %v\n", seq2.IsEmpty(nonEmptySeq))
}

Output

Empty sequence: true
Non-empty sequence: false

IsNotEmpty

func IsNotEmpty[K, V any](seq iter.Seq2[K, V]) bool

IsNotEmpty returns true if the sequence is not empty.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
emptySeq := seq2.Empty[any, any]()

nonEmptySeq := seq2.OfIndexed("a")

fmt.Printf("Empty sequence: %v\n", seq2.IsNotEmpty(emptySeq))
fmt.Printf("Non-empty sequence: %v\n", seq2.IsNotEmpty(nonEmptySeq))
}

Output

Empty sequence: false
Non-empty sequence: true

Keys

func Keys[K, V any](seq iter.Seq2[K, V]) iter.Seq[K]

Keys returns a sequence of keys from a sequence of key-value pairs.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed("a", "b", "c")

keys := seq2.Keys(input)

seq.ForEach(keys, func(k int) {
fmt.Print(k, " ")
})
}

Output

0 1 2

Limit

func Limit[K any, V any](seq iter.Seq2[K, V], n int) iter.Seq2[K, V]

Limit returns a new sequence that contains only the first n elements of the given sequence. SQL-like alias for Take.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

// Limit is an alias for Take
taken := seq2.Limit(input, 3)

result := seq2.CollectToMap(taken)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

Map

func Map[K, V, RK, RV any](seq iter.Seq2[K, V], mapper DoubleMapper[K, V, RK, RV]) iter.Seq2[RK, RV]

Map applies a mapper function to each element of the sequence.

Example
package main

import (
"fmt"
"strings"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Map both key and value to produce a new value (keeps original keys)
mapped := seq2.Map(input, func(k string, v int) (string, int) {
return strings.ToUpper(k), v * 10
})

result := seq2.CollectToMap(mapped)
fmt.Println(result)
}

Output

map[A:10 B:20 C:30]

MapKeys

func MapKeys[K, V, RK any](seq iter.Seq2[K, V], mapper KeyMapper[K, RK]) iter.Seq2[RK, V]

MapKeys applies a mapper function to each key of the sequence.

Example
package main

import (
"fmt"
"strings"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Map keys to uppercase (keeps original values)
mapped := seq2.MapKeys(input, func(k string) string {
return strings.ToUpper(k)
})

result := seq2.CollectToMap(mapped)
fmt.Println(result)
}

Output

map[A:1 B:2 C:3]

MapTo

func MapTo[K, V, RV any](seq iter.Seq2[K, V], mapper Mapper[K, V, RV]) iter.Seq[RV]

MapTo applies a mapper function to each element of the sequence and returns a sequence of mapper results.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Map each key-value pair to a string
mapped := seq2.MapTo(input, func(k string, v int) string {
return fmt.Sprintf("%s=%d", k, v)
})

seq.ForEach(mapped, func(v string) {
fmt.Println(v)
})
}

Output

a=1
b=2
c=3

MapValues

func MapValues[K, V, RV any](seq iter.Seq2[K, V], mapper ValueMapper[V, RV]) iter.Seq2[K, RV]

MapValues applies a mapper function to each value of the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Map values to their squares (keeps original keys)
mapped := seq2.MapValues(input, func(v int) int {
return v * v
})

result := seq2.CollectToMap(mapped)
fmt.Println(result)
}

Output

map[a:1 b:4 c:9]

None

func None[K, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) bool

None returns true if no element satisfies the predicate.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

none := seq2.None(input, func(k string, v int) bool {
return v > 10
})

fmt.Println(none)
}

Output

true

NotContains

func NotContains[K comparable, V any](seq iter.Seq2[K, V], key K) bool

NotContains returns true if the key is not in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

notContains := seq2.NotContains(input, "x")

fmt.Println(notContains)
}

Output

true

NotContainsPair

func NotContainsPair[K comparable, V comparable](seq iter.Seq2[K, V], key K, value V) bool

NotContainsPair returns true if the key-value pair is not in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

notContainsPair := seq2.NotContainsPair(input, "b", 3)

fmt.Println(notContainsPair)
}

Output

true

NotContainsValue

func NotContainsValue[K any, V comparable](seq iter.Seq2[K, V], value V) bool

NotContainsValue returns true if the value is not in the sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

notContainsValue := seq2.NotContainsValue(input, 5)

fmt.Println(notContainsValue)
}

Output

true

OfIndexed

func OfIndexed[E any](elems ...E) iter.Seq2[int, E]

OfIndexed creates a new indexed sequence from the given elements.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence from individual elements
indexed := seq2.OfIndexed(1, 2, 3)

result := seq2.CollectToMap(indexed)
fmt.Println(result)
}

Output

map[0:1 1:2 2:3]

Offset

func Offset[K any, V any](seq iter.Seq2[K, V], n int) iter.Seq2[K, V]

Offset returns a new sequence that skips the first n elements of the given sequence. SQL-like alias for Skip.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed(10, 20, 30, 40, 20)

// Skip the first 2 elements
skipped := seq2.Offset(input, 2)

result := seq2.CollectToMap(skipped)
fmt.Println(result)
}

Output

map[2:30 3:40 4:20]

Prepend

func Prepend[K any, V any](seq iter.Seq2[K, V], key K, value V) iter.Seq2[K, V]

Prepend prepends element to the beginning of a sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Prepend a new key-value pair to the sequence
prepended := seq2.Prepend(input, "a", 1)

result := seq2.CollectToMap(prepended)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

Reduce

func Reduce[K any, V any, R any](seq2 iter.Seq2[K, V], accumulator func(agg R, key K, value V) R, initial R) R

Reduce applies a function against an accumulator and each element in the sequence (from left to right) to reduce it to a single value.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
type Reduced struct {
Key string
Value int
}

input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Reduce to calculate the sum of all values
reduced := seq2.Reduce(input, func(agg Reduced, key string, value int) Reduced {
return Reduced{
Key: agg.Key + key,
Value: agg.Value + value,
}
}, Reduced{})

fmt.Println(reduced)
}

Output

{abc 6}

ReduceRight

func ReduceRight[K any, V any, R any](seq2 iter.Seq2[K, V], accumulator func(agg R, key K, value V) R, initial R) R

ReduceRight applies a function against an accumulator and each element in the sequence (from right to left) to reduce it to a single value.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
type Reduced struct {
Key string
Value int
}

input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Reduce to calculate the sum of all values
reduced := seq2.ReduceRight(input, func(agg Reduced, key string, value int) Reduced {
return Reduced{
Key: agg.Key + key,
Value: agg.Value + value,
}
}, Reduced{})

fmt.Println(reduced)
}

Output

{cba 6}

Repeat

func Repeat[K any, V any, N types.Integer](key K, value V, count N) iter.Seq2[K, V]

Repeat repeats the given pair `count` times.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence that repeats a key-value pair 3 times
repeated := seq2.Repeat("key", 42, 3)

seq2.ForEach(repeated, func(k string, v int) {
fmt.Println(k, ":", v)
})
}

Output

key : 42
key : 42
key : 42

Reverse

func Reverse[K, V any](seq iter.Seq2[K, V]) iter.Seq2[K, V]

Reverse reverses the given sequence.

Example
package main

import (
"fmt"
"strings"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create an indexed sequence
sequence := seq2.OfIndexed("a", "b", "c")

// Reverse it
reversed := seq2.Reverse(sequence)

// CollectToMap into pairs for ordered display
var pairs []string
seq2.ForEach(reversed, func(k int, v string) {
fmt.Println(k, ":", v)
})

fmt.Println(strings.Join(pairs, ", "))
}

Output

2 : c
1 : b
0 : a

Single

func Single[K, V any](k K, v V) iter.Seq2[K, V]

Single returns a sequence with given key value.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence with a single key-value pair
single := seq2.Single("key", 42)

seq2.ForEach(single, func(k string, v int) {
fmt.Println(k, ":", v)
})
}

Output

key : 42

Skip

func Skip[K any, V any](seq iter.Seq2[K, V], n int) iter.Seq2[K, V]

Skip returns a new sequence that skips the first n elements of the given sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed(10, 20, 30, 40, 20)

// Skip the first 2 elements
skipped := seq2.Skip(input, 2)

result := seq2.CollectToMap(skipped)
fmt.Println(result)
}

Output

map[2:30 3:40 4:20]

SkipUntil

func SkipUntil[K any, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) iter.Seq2[K, V]

SkipUntil returns a new sequence that skips elements from the given sequence until the predicate is satisfied.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed(10, 20, 30, 40, 20)

// Skip elements until value of 30 is reached
skipped := seq2.SkipUntil(input, func(k int, v int) bool {
return v == 30
})

result := seq2.CollectToMap(skipped)
fmt.Println(result)
}

Output

map[2:30 3:40 4:20]

SkipWhile

func SkipWhile[K any, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) iter.Seq2[K, V]

SkipWhile returns a new sequence that skips elements from the given sequence while the predicate is satisfied.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed(10, 20, 30, 40, 20)

// Skip elements until the value is less than 30
skipped := seq2.SkipWhile(input, func(k int, v int) bool {
return v < 30
})

result := seq2.CollectToMap(skipped)
fmt.Println(result)
}

Output

map[2:30 3:40 4:20]

SortBy

func SortBy[K any, V any, R types.Ordered](seq iter.Seq2[K, V], mapper func(K, V) R) iter.Seq2[K, V]

SortBy sorts the elements of a sequence by result of the mapper.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.Single("a", 1)
input = seq2.Append(input, "c", 3)
input = seq2.Append(input, "b", 2)

// Sort by values
sorted := seq2.SortBy(input, func(k string, v int) int {
return v
})

seq2.ForEach(sorted, func(k string, v int) {
fmt.Println(k, ":", v)
})
}

Output

a : 1
b : 2
c : 3

SortByKeys

func SortByKeys[K types.Ordered, V any](seq iter.Seq2[K, V]) iter.Seq2[K, V]

SortByKeys sorts the elements of a sequence by key in ascending order.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.Single("a", 1)
input = seq2.Append(input, "c", 3)
input = seq2.Append(input, "b", 2)

// SortByKeys by keys (alphabetically)
sorted := seq2.SortByKeys(input)

seq2.ForEach(sorted, func(k string, v int) {
fmt.Println(k, ":", v)
})
}

Output

a : 1
b : 2
c : 3

SortComparingKeys

func SortComparingKeys[K any, V any](seq iter.Seq2[K, V], cmp func(K, K) int) iter.Seq2[K, V]

SortComparingKeys sorts the elements of a sequence by key in ascending order.

Example
package main

import (
"cmp"
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.Single("a", 1)
input = seq2.Append(input, "c", 3)
input = seq2.Append(input, "b", 2)

// Sort by keys in reverse order
sorted := seq2.SortComparingKeys(input, func(a, b string) int {
return -cmp.Compare(a, b)
})

seq2.ForEach(sorted, func(k string, v int) {
fmt.Println(k, ":", v)
})
}

Output

c : 3
b : 2
a : 1

SortComparingValues

func SortComparingValues[K any, V any](seq iter.Seq2[K, V], cmp func(V, V) int) iter.Seq2[K, V]

SortComparingValues sorts the elements of a sequence by value in ascending order.

Example
package main

import (
"cmp"
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Unordered map with string keys
input := seq2.Single("a", 1)
input = seq2.Append(input, "c", 3)
input = seq2.Append(input, "b", 2)

// Sort by values in descending order
sorted := seq2.SortComparingValues(input, func(a, b int) int {
return -cmp.Compare(a, b)
})

seq2.ForEach(sorted, func(k string, v int) {
fmt.Println(k, ":", v)
})
}

Output

c : 3
b : 2
a : 1

Split

func Split[K any, V any](seq iter.Seq2[K, V]) (iter.Seq[K], iter.Seq[V])

Split splits a sequence of pairs into two sequences.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// Split is an alias for UnZip
keys, values := seq2.Split(input)

keySlice := make([]string, 0)
for k := range keys {
keySlice = append(keySlice, k)
}
fmt.Printf("Keys: %v\n", keySlice)

valueSlice := make([]int, 0)
for v := range values {
valueSlice = append(valueSlice, v)
}
fmt.Printf("Values: %v\n", valueSlice)
}

Output

Keys: [a b c]
Values: [1 2 3]

Take

func Take[K any, V any](seq iter.Seq2[K, V], n int) iter.Seq2[K, V]

Take returns a new sequence that contains only the first n elements of the given sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

// Take the first 2 elements
taken := seq2.Take(input, 2)

result := seq2.CollectToMap(taken)
fmt.Println(result)
}

Output

map[a:1 b:2]

TakeUntil

func TakeUntil[K any, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) iter.Seq2[K, V]

TakeUntil returns a new sequence that takes elements from the given sequence until the predicate is satisfied.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

// Take elements until value is greater than 2
taken := seq2.TakeUntil(input, func(k string, v int) bool {
return v > 2
})

result := seq2.CollectToMap(taken)
fmt.Println(result)
}

Output

map[a:1 b:2]

TakeWhile

func TakeWhile[K any, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) iter.Seq2[K, V]

TakeWhile returns a new sequence that takes elements from the given sequence while the predicate is satisfied.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed("a", "b", "c", "d")

// Take elements while value is less than 3
taken := seq2.TakeWhile(input, func(k int, v string) bool {
return v != "c"
})

result := seq2.CollectToMap(taken)
fmt.Println(result)
}

Output

map[0:a 1:b]

Tap

func Tap[K any, V any](seq iter.Seq2[K, V], consumer Consumer[K, V]) iter.Seq2[K, V]

Tap returns a sequence that applies the given consumer to each element of the input sequence and pass it further.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
// Ensure to have consistent output
input = seq2.SortByKeys(input)

// Use Tap to print key-value pairs while passing them through
tapped := seq2.Tap(input, func(k string, v int) {
fmt.Printf("Processing: %s => %d\n", k, v)
})

seq2.Flush(tapped)

}

Output

Processing: a => 1
Processing: b => 2
Processing: c => 3

Tick

func Tick(d time.Duration) iter.Seq2[int, time.Time]

Tick returns a sequence that yields the tick number and the current time every duration.

Example
package main

import (
"fmt"
"time"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
ticker := seq2.Tick(1 * time.Millisecond)

ticker = seq2.Take(ticker, 5)

seq2.ForEach(ticker, func(tick int, v time.Time) {
fmt.Printf("tick %d at %s \n", tick, v.Format("15:04:05.000"))
})

// Example Output:
// tick 1 at 00:00:00.000
// tick 2 at 00:00:00.001
// tick 3 at 00:00:00.002
// tick 4 at 00:00:00.003
// tick 5 at 00:00:00.004
}

ToMap

func ToMap[Map ~map[K]V, K comparable, V any](seq iter.Seq2[K, V], m Map)

ToMap collects the elements of the given sequence into a map.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

result := make(map[string]int, 3)
seq2.ToMap(input, result)

fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

UnZip

func UnZip[K any, V any](seq iter.Seq2[K, V]) (iter.Seq[K], iter.Seq[V])

UnZip splits a sequence of pairs into two sequences.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
input = seq2.SortByKeys(input)

// UnZip splits a sequence into keys and values sequences
keys, values := seq2.UnZip(input)

keySlice := make([]string, 0)
for k := range keys {
keySlice = append(keySlice, k)
}
fmt.Printf("Keys: %v\n", keySlice)

valueSlice := make([]int, 0)
for v := range values {
valueSlice = append(valueSlice, v)
}
fmt.Printf("Values: %v\n", valueSlice)
}

Output

Keys: [a b c]
Values: [1 2 3]
Example (After Zip)
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
nums := seq.Of(1, 2, 3)
letters := seq.Of("a", "b", "c")

zipped := seq.Zip(nums, letters)

unzipped1, unzipped2 := seq2.UnZip(zipped)

result1 := seq.Collect(unzipped1)
result2 := seq.Collect(unzipped2)

fmt.Println(result1)
fmt.Println(result2)
}

Output

[1 2 3]
[a b c]

Union

func Union[K comparable, V comparable](seq1 iter.Seq2[K, V], seq2 iter.Seq2[K, V]) iter.Seq2[K, V]

Union returns a sequence that contains all distinct elements from both input sequences.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
first := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3})
first = seq2.SortByKeys(first)
second := seq2.FromMap(map[string]int{"c": 3, "d": 4, "e": 5})
second = seq2.SortByKeys(second)

// Union returns distinct elements from both sequences
combined := seq2.Union(first, second)

result := seq2.CollectToMap(combined)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3 d:4 e:5]

UnionAll

func UnionAll[K any, V any](seq1 iter.Seq2[K, V], seq2 iter.Seq2[K, V]) iter.Seq2[K, V]

UnionAll returns a sequence that contains all elements from both input sequences.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
first := seq2.FromMap(map[string]int{"a": 1, "b": 2})
first = seq2.SortByKeys(first)
second := seq2.FromMap(map[string]int{"c": 3, "b": 2})
second = seq2.SortByKeys(second)

// UnionAll is an alias for Concat
combined := seq2.UnionAll(first, second)

result := seq2.CollectToMap(combined)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

Uniq

func Uniq[K comparable, V comparable](seq iter.Seq2[K, V]) iter.Seq2[K, V]

Uniq returns a new sequence that contains only the unique elements of the given sequence. It compares both key and value. In case of pointers, pointers are compared, not the values they point to.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence with duplicate key-value pairs
input := seq2.Concat(
seq2.FromMap(map[string]int{"a": 1, "b": 2}),
seq2.FromMap(map[string]int{"a": 1, "c": 3}),
)

// Get unique key-value pairs
unique := seq2.Uniq(input)

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[a:1 b:2 c:3]

UniqBy

func UniqBy[K any, V any, K2 comparable](seq iter.Seq2[K, V], mapper Mapper[K, V, K2]) iter.Seq2[K, V]

UniqBy returns a new sequence that contains only the unique elements of the given sequence based on result of the mapper.

Example
package main

import (
"fmt"
"strconv"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"apple": 1, "banana": 2, "apricot": 3, "berry": 4, "blueberry": 5})
input = seq2.SortByKeys(input)

// Get unique entries based on first letter and value modulo 2
unique := seq2.UniqBy(input, func(k string, v int) string {
return string(k[0]) + strconv.Itoa(v%2)
})

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[apple:1 banana:2 blueberry:5]

UniqByKeys

func UniqByKeys[K any, V any, K2 comparable](seq iter.Seq2[K, V], mapper KeyMapper[K, K2]) iter.Seq2[K, V]

UniqByKeys returns a new sequence that contains only the unique elements of the given sequence based on a result of key mapper.

Example
package main

import (
"fmt"
"strings"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"Apple": 1, "apricot": 2, "Banana": 3, "berry": 4})
input = seq2.SortByKeys(input)

// Get unique entries based on lowercase first letter of key
unique := seq2.UniqByKeys(input, func(k string) string {
return strings.ToLower(string(k[0]))
})

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[Apple:1 Banana:3]

UniqByValues

func UniqByValues[K any, V any, V2 comparable](seq iter.Seq2[K, V], mapper ValueMapper[V, V2]) iter.Seq2[K, V]

UniqByValues returns a new sequence that contains only the unique elements of the given sequence based on a result of value mapper.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 10, "b": 21, "c": 30, "d": 44})
input = seq2.SortByKeys(input)

// Get unique entries based on value modulo 10
unique := seq2.UniqByValues(input, func(v int) int {
return v % 10
})

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[a:10 b:21 d:44]

UniqKeys

func UniqKeys[K comparable, V any](seq iter.Seq2[K, V]) iter.Seq2[K, V]

UniqKeys returns a new sequence that contains only the elements with unique keys from the given sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence with duplicate keys
input := seq2.Concat(
seq2.FromMap(map[string]int{"a": 1, "b": 2}),
seq2.FromMap(map[string]int{"a": 3, "c": 4}),
)

// Get entries with unique keys (first occurrence wins)
unique := seq2.UniqKeys(input)

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[a:1 b:2 c:4]

UniqValues

func UniqValues[K any, V comparable](seq iter.Seq2[K, V]) iter.Seq2[K, V]

UniqValues returns a new sequence that contains only the elements with unique values from the given sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a sequence with duplicate values
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 1, "d": 3})
input = seq2.SortByKeys(input)

// Get entries with unique values (first occurrence wins)
unique := seq2.UniqValues(input)

result := seq2.CollectToMap(unique)
fmt.Println(result)
}

Output

map[a:1 b:2 d:3]

Values

func Values[K, V any](seq iter.Seq2[K, V]) iter.Seq[V]

Values returns a sequence of values from a sequence of key-value pairs.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.OfIndexed("a", "b", "c")

keys := seq2.Values(input)

seq.ForEach(keys, func(v string) {
fmt.Print(v, " ")
})
}

Output

a b c

Where

func Where[K any, V any](seq iter.Seq2[K, V], predicate Predicate[K, V]) iter.Seq2[K, V]

Where returns a new sequence that contains only the elements that satisfy the predicate. SQL-like alias for Filter

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
input := seq2.FromMap(map[string]int{"a": 1, "b": 2, "c": 3, "d": 4})
input = seq2.SortByKeys(input)

// Where is an alias for Filter
filtered := seq2.Where(input, func(k string, v int) bool {
return v > 2
})

result := seq2.CollectToMap(filtered)
fmt.Println(result)
}

Output

map[c:3 d:4]

WithIndex

func WithIndex[E any](seq iter.Seq[E]) iter.Seq2[int, E]

WithIndex creates a new indexed sequence from the given sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create a iter.Seq of values
values := seq.Of("a", "b", "c")

// Add indexes
indexed := seq2.WithIndex(values)

result := seq2.CollectToMap(indexed)
fmt.Println(result)
}

Output

map[0:a 1:b 2:c]

WithoutIndex

func WithoutIndex[E any](indexed iter.Seq2[int, E]) iter.Seq[E]

WithoutIndex creates a new sequence from the given indexed sequence.

Example
package main

import (
"fmt"

"github.com/go-softwarelab/common/pkg/seq"
"github.com/go-softwarelab/common/pkg/seq2"
)

func main() {
// Create an indexed sequence
indexed := seq2.OfIndexed("a", "b", "c")

// Remove indexes
values := seq2.WithoutIndex(indexed)

result := seq.Collect(values)
fmt.Println(result)
}

Output

[a b c]

type Consumer

Consumer is a function that consumes an element of an iter.Seq2.

type Consumer[K any, V any] = func(K, V)

type DoubleMapper

DoubleMapper is a function that takes an element and returns a new sequence element.

type DoubleMapper[K, V, RK, RV any] = func(K, V) (RK, RV)

type KeyMapper

KeyMapper is a function that takes Key a new Key.

type KeyMapper[K, R any] = func(K) R

type KeyPredicate

KeyPredicate is a function that is used to filter by key.

type KeyPredicate[E any] = KeyMapper[E, bool]

type Mapper

Mapper is a function that takes an element and returns a new element.

type Mapper[K, V, R any] = func(K, V) R

type Predicate

Predicate is a function that takes an element and returns a boolean.

type Predicate[K any, V any] = Mapper[K, V, bool]

type ValueMapper

ValueMapper is a function that takes Value a new Value.

type ValueMapper[V, R any] = func(V) R

type ValuePredicate

ValuePredicate is a function that is used to filter by value.

type ValuePredicate[E any] = ValueMapper[E, bool]