Files
phishingclub/backend/vendor/github.com/enetx/g/seq2.go
T
RonniSkansing 2028391c3c vendor backend
Signed-off-by: RonniSkansing <rskansing@gmail.com>
2026-09-16 23:17:35 +02:00

1153 lines
30 KiB
Go

package g
import (
"context"
"iter"
"reflect"
"slices"
"github.com/enetx/g/cmp"
"github.com/enetx/g/constraints"
)
// Seq2 is an iterator over sequences of ordered pairs of values, most commonly ordered key-value pairs.
type Seq2[K, V any] func(yield func(K, V) bool)
// Pull converts the “push-style” iterator sequence seq
// into a “pull-style” iterator accessed by the two functions
// next and stop.
//
// Next returns the next pair in the sequence
// and a boolean indicating whether the pair is valid.
// When the sequence is over, next returns a pair of zero values and false.
// It is valid to call next after reaching the end of the sequence
// or after calling stop. These calls will continue
// to return a pair of zero values and false.
//
// Stop ends the iteration. It must be called when the caller is
// no longer interested in next values and next has not yet
// signaled that the sequence is over (with a false boolean return).
// It is valid to call stop multiple times and when next has
// already returned false.
//
// It is an error to call next or stop from multiple goroutines
// simultaneously.
func (seq Seq2[K, V]) Pull() (func() (K, V, bool), func()) {
return seq.seq2Pull()
}
// All checks whether all key-value pairs in the iterator satisfy the provided condition.
// This function is useful when you want to determine if all pairs in an iterator
// meet a specific criteria.
//
// Parameters:
// - fn (func(K, V) bool): A function that returns a boolean indicating whether the pair satisfies
// the condition.
//
// Returns:
// - bool: True if all pairs in the iterator satisfy the condition, false otherwise.
//
// Example usage:
//
// m := g.NewMapOrd[g.String, g.Int]()
// m.Insert("a", 1)
// m.Insert("b", 2)
// allPositive := m.Iter().All(func(_ g.String, v g.Int) bool { return v > 0 })
//
// The resulting allPositive will be true if all values returned by the iterator are positive.
func (seq Seq2[K, V]) All(fn func(K, V) bool) bool {
all := true
seq(func(k K, v V) bool {
if !fn(k, v) {
all = false
return false
}
return true
})
return all
}
// Any checks whether any key-value pair in the iterator satisfies the provided condition.
// This function is useful when you want to determine if at least one pair in an iterator
// meets a specific criteria.
//
// Parameters:
// - fn (func(K, V) bool): A function that returns a boolean indicating whether the pair satisfies
// the condition.
//
// Returns:
// - bool: True if at least one pair in the iterator satisfies the condition, false otherwise.
//
// Example usage:
//
// m := g.NewMapOrd[g.String, g.Int]()
// m.Insert("a", 1)
// m.Insert("b", 2)
// anyEven := m.Iter().Any(func(_ g.String, v g.Int) bool { return v%2 == 0 })
//
// The resulting anyEven will be true if at least one value returned by the iterator is even.
func (seq Seq2[K, V]) Any(fn func(K, V) bool) bool {
found := false
seq(func(k K, v V) bool {
if fn(k, v) {
found = true
return false
}
return true
})
return found
}
// Keys returns an iterator over the keys of the key-value pairs.
func (seq Seq2[K, V]) Keys() Seq[K] {
return func(yield func(K) bool) { seq(func(k K, _ V) bool { return yield(k) }) }
}
// Values returns an iterator over the values of the key-value pairs.
func (seq Seq2[K, V]) Values() Seq[V] {
return func(yield func(V) bool) { seq(func(_ K, v V) bool { return yield(v) }) }
}
// Unzip consumes the sequence and collects the keys and values
// of each pair into two separate slices.
func (seq Seq2[K, V]) Unzip() (Slice[K], Slice[V]) {
var (
keys Slice[K]
values Slice[V]
)
seq(func(k K, v V) bool {
keys = append(keys, k)
values = append(values, v)
return true
})
return keys, values
}
// SortBy applies a custom sorting function to the elements in the iterator
// and returns a new iterator containing the sorted elements.
//
// The sorting function 'fn' should take two arguments, 'a' and 'b', of type Pair[K, V],
// and return a cmp.Ordering: cmp.Less orders 'a' before 'b', cmp.More after it.
//
// Example:
//
// m := g.NewMapOrd[g.Int, g.String]()
// m.Insert(6, "bb")
// m.Insert(0, "dd")
// m.Insert(1, "aa")
// m.Insert(5, "xx")
// m.Insert(2, "cc")
// m.Insert(3, "ff")
// m.Insert(4, "zz")
//
// m.Iter().
// SortBy(
// func(a, b g.Pair[g.Int, g.String]) cmp.Ordering {
// return a.Key.Cmp(b.Key)
// // return a.Value.Cmp(b.Value)
// }).
// Collect().
// MapOrd[g.Int, g.String]().
// Print()
//
// Output: MapOrd{0:dd, 1:aa, 2:cc, 3:ff, 4:zz, 5:xx, 6:bb}
//
// The returned iterator is of type Seq2[K, V], which implements the iterator
// interface for further iteration over the sorted elements.
func (seq Seq2[K, V]) SortBy(fn func(a, b Pair[K, V]) cmp.Ordering) Seq2[K, V] {
buf := seq.seq2ToPairs()
slices.SortFunc(buf, func(a, b Pair[K, V]) int { return int(fn(a, b)) })
return seqFromPairs(buf)
}
// SortByKey applies a custom sorting function to the keys in the iterator
// and returns a new iterator containing the sorted elements.
//
// The sorting function 'fn' should take two arguments, 'a' and 'b', of type K,
// and return a cmp.Ordering: cmp.Less orders 'a' before 'b', cmp.More after it.
//
// Example:
//
// m := g.NewMapOrd[g.Int, g.String]()
// m.Insert(6, "bb")
// m.Insert(0, "dd")
// m.Insert(1, "aa")
// m.Insert(5, "xx")
// m.Insert(2, "cc")
// m.Insert(3, "ff")
// m.Insert(4, "zz")
//
// m.Iter().
// SortByKey(g.Int.Cmp).
// Collect().
// MapOrd[g.Int, g.String]().
// Print()
//
// Output: MapOrd{0:dd, 1:aa, 2:cc, 3:ff, 4:zz, 5:xx, 6:bb}
func (seq Seq2[K, V]) SortByKey(fn func(a, b K) cmp.Ordering) Seq2[K, V] {
buf := seq.seq2ToPairs()
slices.SortFunc(buf, func(a, b Pair[K, V]) int { return int(fn(a.Key, b.Key)) })
return seqFromPairs(buf)
}
// SortByValue applies a custom sorting function to the values in the iterator
// and returns a new iterator containing the sorted elements.
//
// The sorting function 'fn' should take two arguments, 'a' and 'b', of type V,
// and return a cmp.Ordering: cmp.Less orders 'a' before 'b', cmp.More after it.
//
// Example:
//
// m := g.NewMapOrd[g.Int, g.String]()
// m.Insert(6, "bb")
// m.Insert(0, "dd")
// m.Insert(1, "aa")
// m.Insert(5, "xx")
// m.Insert(2, "cc")
// m.Insert(3, "ff")
// m.Insert(4, "zz")
//
// m.Iter().
// SortByValue(g.String.Cmp).
// Collect().
// MapOrd[g.Int, g.String]().
// Print()
//
// Output: MapOrd{1:aa, 6:bb, 2:cc, 0:dd, 3:ff, 5:xx, 4:zz}
func (seq Seq2[K, V]) SortByValue(fn func(a, b V) cmp.Ordering) Seq2[K, V] {
buf := seq.seq2ToPairs()
slices.SortFunc(buf, func(a, b Pair[K, V]) int { return int(fn(a.Value, b.Value)) })
return seqFromPairs(buf)
}
// Inspect creates a new iterator that wraps around the current iterator
// and allows inspecting each key-value pair as it passes through.
func (seq Seq2[K, V]) Inspect(fn func(k K, v V)) Seq2[K, V] {
return func(yield func(K, V) bool) { seq(func(k K, v V) bool { fn(k, v); return yield(k, v) }) }
}
// StepBy creates a new iterator that iterates over every N-th element of the original iterator.
// This function is useful when you want to skip a specific number of elements between each iteration.
//
// Parameters:
// - n Int: The step size, indicating how many elements to skip between each iteration.
//
// Returns:
// - Seq2[K, V]: A new iterator that produces key-value pairs from the original iterator with a step size of N.
//
// Example usage:
//
// mapIter := g.MapOrd[string, int]{{"one", 1}, {"two", 2}, {"three", 3}}.Iter()
// iter := mapIter.StepBy(2)
// iter.Collect().MapOrd[string, int]().Print()
//
// Output: MapOrd{one:1, three:3}
//
// The resulting iterator will produce key-value pairs from the original iterator with a step size of N.
func (seq Seq2[K, V]) StepBy(n Int) Seq2[K, V] {
return func(yield func(K, V) bool) {
if n <= 0 {
return
}
index := Int(0)
seq(func(k K, v V) bool {
if index%n == 0 {
if !yield(k, v) {
return false
}
}
index++
return true
})
}
}
// Chain concatenates the current iterator with other iterators, returning a new iterator.
//
// The function creates a new iterator that combines the elements of the current iterator
// with elements from the provided iterators in the order they are given.
//
// Params:
//
// - seqs ([]Seq2[K, V]): Other iterators to be concatenated with the current iterator.
//
// Returns:
//
// - Seq2[K, V]: A new iterator containing elements from the current iterator and the provided iterators.
//
// Example usage:
//
// m1 := g.NewMapOrd[int, string]()
// m1.Insert(1, "a")
//
// m2 := g.NewMapOrd[int, string]()
// m2.Insert(2, "b")
//
// // Concatenating iterators and collecting the result.
// m1.Iter().Chain(m2.Iter()).Collect().MapOrd[int, string]().Print()
//
// Output: MapOrd{1:a, 2:b}
//
// The resulting iterator will contain elements from both iterators in the specified order.
func (seq Seq2[K, V]) Chain(seqs ...Seq2[K, V]) Seq2[K, V] {
return func(yield func(K, V) bool) {
proceed := true
seq(func(k K, v V) bool {
if !yield(k, v) {
proceed = false
return false
}
return true
})
if !proceed {
return
}
for _, rest := range seqs {
rest(func(k K, v V) bool {
if !yield(k, v) {
proceed = false
return false
}
return true
})
if !proceed {
return
}
}
}
}
// Count consumes the iterator, counting the number of iterations and returning it.
func (seq Seq2[K, V]) Count() Int {
count := Int(0)
seq(func(K, V) bool { count++; return true })
return count
}
// Skip returns a new iterator skipping the first n elements.
//
// The function creates a new iterator that skips the first n elements of the current iterator
// and returns an iterator starting from the (n+1)th element.
//
// Params:
//
// - n (Int): The number of elements to skip from the beginning of the iterator.
// Negative values are treated as zero.
//
// Returns:
//
// - Seq2[K, V]: An iterator that starts after skipping the first n elements.
//
// Example usage:
//
// m := g.NewMapOrd[int, string]()
// m.Insert(1, "a")
// m.Insert(2, "b")
// m.Insert(3, "c")
// m.Insert(4, "d")
//
// // Skipping the first two elements and collecting the rest.
// m.Iter().Skip(2).Collect().MapOrd[int, string]().Print()
//
// Output: MapOrd{3:c, 4:d}
//
// The resulting iterator will start after skipping the specified number of elements.
func (seq Seq2[K, V]) Skip(n Int) Seq2[K, V] {
return func(yield func(K, V) bool) {
if n <= 0 {
seq(yield)
return
}
count := Int(0)
seq(func(k K, v V) bool {
if count < n {
count++
return true
}
return yield(k, v)
})
}
}
// Exclude returns a new iterator excluding elements that satisfy the provided function.
//
// The function creates a new iterator excluding elements from the current iterator
// for which the provided function returns true.
//
// Params:
//
// - fn (func(K, V) bool): The function used to determine exclusion criteria for elements.
//
// Returns:
//
// - Seq2[K, V]: A new iterator excluding elements that satisfy the given condition.
//
// Example usage:
//
// mo := g.NewMapOrd[int, int]()
// mo.Insert(1, 1)
// mo.Insert(2, 2)
// mo.Insert(3, 3)
// mo.Insert(4, 4)
// mo.Insert(5, 5)
//
// notEven := mo.Iter().
// Exclude(
// func(k, v int) bool {
// return v%2 == 0
// }).
// Collect().MapOrd[int, int]()
// notEven.Print()
//
// Output: MapOrd{1:1, 3:3, 5:5}
//
// The resulting iterator will exclude elements based on the provided condition.
func (seq Seq2[K, V]) Exclude(fn func(K, V) bool) Seq2[K, V] {
return func(yield func(K, V) bool) {
seq(func(k K, v V) bool {
if !fn(k, v) {
return yield(k, v)
}
return true
})
}
}
// Filter returns a new iterator containing only the elements that satisfy the provided function.
//
// The function creates a new iterator including elements from the current iterator
// for which the provided function returns true.
//
// Params:
//
// - fn (func(K, V) bool): The function used to determine inclusion criteria for elements.
//
// Returns:
//
// - Seq2[K, V]: A new iterator containing elements that satisfy the given condition.
//
// Example usage:
//
// mo := g.NewMapOrd[int, int]()
// mo.Insert(1, 1)
// mo.Insert(2, 2)
// mo.Insert(3, 3)
// mo.Insert(4, 4)
// mo.Insert(5, 5)
//
// even := mo.Iter().
// Filter(
// func(k, v int) bool {
// return v%2 == 0
// }).
// Collect().MapOrd[int, int]()
// even.Print()
//
// Output: MapOrd{2:2, 4:4}
//
// The resulting iterator will include elements based on the provided condition.
func (seq Seq2[K, V]) Filter(fn func(K, V) bool) Seq2[K, V] {
return func(yield func(K, V) bool) {
seq(func(k K, v V) bool {
if fn(k, v) {
return yield(k, v)
}
return true
})
}
}
// FilterByKey returns a new iterator lazily yielding only the pairs whose key
// satisfies the provided predicate; values are not inspected.
//
// It lifts a single-parameter predicate to the pair-wise Filter — composes
// with f.* factories:
//
// mo.Iter().FilterByKey(f.Eq("host"))
func (seq Seq2[K, V]) FilterByKey(fn func(K) bool) Seq2[K, V] {
return seq.Filter(func(k K, _ V) bool { return fn(k) })
}
// FilterByValue returns a new iterator lazily yielding only the pairs whose
// value satisfies the provided predicate; keys are not inspected.
//
// It lifts a single-parameter predicate to the pair-wise Filter — composes
// with f.* factories:
//
// mo.Iter().FilterByValue(f.Gt(10))
func (seq Seq2[K, V]) FilterByValue(fn func(V) bool) Seq2[K, V] {
return seq.Filter(func(_ K, v V) bool { return fn(v) })
}
// Find searches for an element in the iterator that satisfies the provided function.
//
// The function iterates through the elements of the iterator and returns the first element
// for which the provided function returns true.
//
// Params:
//
// - fn (func(K, V) bool): The function used to test elements for a condition.
//
// Returns:
//
// - Option[Pair[K, V]]: An Option containing the first pair that satisfies the condition; None if not found.
//
// Example usage:
//
// m := g.NewMapOrd[int, int]()
// m.Insert(1, 1)
// f := m.Iter().Find(func(_ int, v int) bool { return v == 1 })
// if f.IsSome() {
// print(f.Some().Key)
// }
//
// The resulting Option may contain the first element that satisfies the condition, or None if not found.
func (seq Seq2[K, V]) Find(fn func(k K, v V) bool) Option[Pair[K, V]] {
var result Option[Pair[K, V]]
seq(func(k K, v V) bool {
if fn(k, v) {
result = Some(Pair[K, V]{Key: k, Value: v})
return false
}
return true
})
return result
}
// ForEach iterates through all elements and applies the given function to each key-value pair.
//
// The function applies the provided function to each key-value pair in the iterator.
//
// Params:
//
// - fn (func(K, V)): The function to be applied to each key-value pair in the iterator.
//
// Example usage:
//
// m := g.NewMapOrd[int, int]()
// m.Insert(1, 1)
// m.Insert(2, 2)
// m.Insert(3, 3)
// m.Insert(4, 4)
// m.Insert(5, 5)
//
// m.Iter().ForEach(func(key, val int) {
// // Process key-value pair
// })
//
// The provided function will be applied to each key-value pair in the iterator.
func (seq Seq2[K, V]) ForEach(fn func(k K, v V)) {
seq(func(k K, v V) bool { fn(k, v); return true })
}
// Map creates a new iterator by applying the given function to each key-value pair.
//
// The function creates a new iterator by applying the provided function to each key-value pair in the iterator.
//
// Params:
//
// - transform (func(K, V) (K2, V2)): The function used to transform each key-value pair
// in the iterator. The key and value types of the result may differ.
//
// Returns:
//
// - Seq2[K2, V2]: A new iterator containing transformed key-value pairs.
//
// Example usage:
//
// mo := g.NewMapOrd[int, int]()
// mo.Insert(1, 1)
// mo.Insert(2, 2)
// mo.Insert(3, 3)
// mo.Insert(4, 4)
// mo.Insert(5, 5)
//
// momap := mo.Iter().
// Map(
// func(k, v int) (int, int) {
// return k * k, v * v
// }).
// Collect().MapOrd[int, int]()
//
// momap.Print()
//
// Output: MapOrd{1:1, 4:4, 9:9, 16:16, 25:25}
//
// The resulting iterator will contain transformed key-value pairs.
func (seq Seq2[K, V]) Map[K2, V2 any](transform func(K, V) (K2, V2)) Seq2[K2, V2] {
return func(yield func(K2, V2) bool) {
seq(func(k K, v V) bool { return yield(transform(k, v)) })
}
}
// FilterMap applies a function to each key-value pair and filters out None results.
//
// Pairs where the function returns None are filtered out; pairs where it returns
// Some(Pair) are transformed and included in the result. Key and value types may differ
// from the input types.
func (seq Seq2[K, V]) FilterMap[K2, V2 any](fn func(K, V) Option[Pair[K2, V2]]) Seq2[K2, V2] {
return func(yield func(K2, V2) bool) {
seq(func(k K, v V) bool {
if pair, ok := fn(k, v).Option(); ok {
return yield(pair.Unpack())
}
return true
})
}
}
// Range iterates through elements until the given function returns false.
//
// The function iterates through the key-value pairs in the iterator, applying the provided function to each pair.
// It continues iterating until the function returns false.
//
// Params:
//
// - fn (func(K, V) bool): The function to be applied to each key-value pair in the iterator.
//
// Example usage:
//
// m := g.NewMapOrd[int, int]()
// m.Insert(1, 1)
// m.Insert(2, 2)
// m.Insert(3, 3)
// m.Insert(4, 4)
// m.Insert(5, 5)
//
// m.Iter().Range(func(k, v int) bool {
// fmt.Println(v) // Replace this with the function logic you need.
// return v < 5 // Replace this with the condition for continuing iteration.
// })
//
// The iteration will stop when the provided function returns false.
func (seq Seq2[K, V]) Range(fn func(k K, v V) bool) {
seq(fn)
}
// Context allows the iteration to be controlled with a context.Context.
func (seq Seq2[K, V]) Context(ctx context.Context) Seq2[K, V] {
return func(yield func(K, V) bool) {
if err := ctx.Err(); err != nil {
return
}
seq(func(k K, v V) bool {
select {
case <-ctx.Done():
return false
default:
return yield(k, v)
}
})
}
}
// Take returns a new iterator with the first n elements.
// The function creates a new iterator containing the first n elements from the original iterator.
func (seq Seq2[K, V]) Take(n Int) Seq2[K, V] {
return func(yield func(K, V) bool) {
if n <= 0 {
return
}
count := Int(0)
seq(func(k K, v V) bool {
if count >= n {
return false
}
count++
return yield(k, v)
})
}
}
// First returns the first key-value pair from the sequence.
func (seq Seq2[K, V]) First() Option[Pair[K, V]] {
var result Option[Pair[K, V]]
seq(func(k K, v V) bool {
result = Some(Pair[K, V]{Key: k, Value: v})
return false
})
return result
}
// Last returns the last key-value pair from the sequence.
func (seq Seq2[K, V]) Last() Option[Pair[K, V]] {
var result Option[Pair[K, V]]
seq(func(k K, v V) bool {
result = Some(Pair[K, V]{Key: k, Value: v})
return true
})
return result
}
// Nth returns the nth key-value pair (0-indexed) in the sequence.
func (seq Seq2[K, V]) Nth(n Int) Option[Pair[K, V]] {
var result Option[Pair[K, V]]
index := Int(0)
seq(func(k K, v V) bool {
if index == n {
result = Some(Pair[K, V]{Key: k, Value: v})
return false
}
index++
return true
})
return result
}
// Chan converts the iterator into a channel, optionally with context(s).
//
// The function converts the key-value pairs from the iterator into a channel, allowing iterative processing
// using channels. It can be used to stream key-value pairs for concurrent or asynchronous operations.
//
// Params:
//
// - ctxs (...context.Context): Optional context(s) that can be used to cancel or set deadlines for the operation.
//
// Returns:
//
// - chan Pair[K, V]: A channel emitting key-value pairs from the iterator.
//
// Example usage:
//
// m := g.NewMapOrd[int, int]()
// m.Insert(1, 1)
// m.Insert(2, 2)
// m.Insert(3, 3)
// m.Insert(4, 4)
// m.Insert(5, 5)
//
// ctx, cancel := context.WithCancel(context.Background())
// defer cancel() // Ensure cancellation to avoid goroutine leaks.
//
// ch := m.Iter().Chan(ctx)
// for pair := range ch {
// // Process key-value pair from the channel
// }
//
// The function converts the iterator into a channel to allow sequential or concurrent processing of key-value pairs.
func (seq Seq2[K, V]) Chan(ctxs ...context.Context) chan Pair[K, V] {
ctx := context.Background()
if len(ctxs) > 0 {
ctx = ctxs[0]
}
ch := make(chan Pair[K, V])
go func() {
defer close(ch)
if err := ctx.Err(); err != nil {
return
}
seq(func(k K, v V) bool {
select {
case <-ctx.Done():
return false
case ch <- Pair[K, V]{k, v}:
return true
}
})
}()
return ch
}
// Next extracts the next key-value pair from the iterator and advances it.
//
// This method consumes the next key-value pair from the iterator and returns them wrapped in an Option.
// The iterator itself is modified to point to the remaining elements.
//
// Returns:
// - Option[Pair[K, V]]: Some(Pair{Key, Value}) if a pair exists, None if the iterator is exhausted.
func (seq *Seq2[K, V]) Next() Option[Pair[K, V]] {
if key, value, remaining, ok := (*seq).seq2Next(); ok {
*seq = Seq2[K, V](remaining)
return Some(Pair[K, V]{Key: key, Value: value})
}
return None[Pair[K, V]]()
}
// Fold reduces the sequence of key-value pairs to a single value using an accumulator.
// The accumulator type may differ from the key and value types.
func (seq Seq2[K, V]) Fold[A any](init A, fn func(acc A, k K, v V) A) A {
seq(func(k K, v V) bool { init = fn(init, k, v); return true })
return init
}
// SumBy maps each key-value pair to a numeric value via fn and returns the sum of those values,
// visiting pairs in insertion order. An empty sequence yields the zero value of S.
func (seq Seq2[K, V]) SumBy[S constraints.Number](fn func(K, V) S) S {
var zero S
return seq.Fold(zero, func(acc S, k K, v V) S { return acc + fn(k, v) })
}
// ProductBy maps each key-value pair to a numeric value via fn and returns their
// product, in insertion order. An empty sequence yields the multiplicative
// identity, one.
func (seq Seq2[K, V]) ProductBy[S constraints.Number](fn func(K, V) S) S {
return seq.Fold(S(1), func(acc S, k K, v V) S { return acc * fn(k, v) })
}
// FindMap applies fn to each key-value pair in insertion order and returns the
// first Some result, or None if fn returns None for every pair.
func (seq Seq2[K, V]) FindMap[U any](fn func(K, V) Option[U]) Option[U] {
var result Option[U]
seq(func(k K, v V) bool {
if o := fn(k, v); o.IsSome() {
result = o
return false
}
return true
})
return result
}
// TryMap applies a fallible transform to each key-value pair and enters the
// Result pipeline, producing a SeqResult[U]. See [Seq.TryMap] for the full
// contract.
func (seq Seq2[K, V]) TryMap[U any](fn func(K, V) Result[U]) SeqResult[U] {
return func(yield func(Result[U]) bool) {
seq(func(k K, v V) bool {
return yield(fn(k, v))
})
}
}
// TakeWhile yields key-value pairs while the predicate returns true, stopping at the first false.
func (seq Seq2[K, V]) TakeWhile(fn func(K, V) bool) Seq2[K, V] {
return func(yield func(K, V) bool) {
seq(func(k K, v V) bool {
if !fn(k, v) {
return false
}
return yield(k, v)
})
}
}
// SkipWhile skips key-value pairs while the predicate returns true, then yields the rest.
func (seq Seq2[K, V]) SkipWhile(fn func(K, V) bool) Seq2[K, V] {
return func(yield func(K, V) bool) {
skipping := true
seq(func(k K, v V) bool {
if skipping && fn(k, v) {
return true
}
skipping = false
return yield(k, v)
})
}
}
// Dedup returns a new iterator that removes consecutive pairs with duplicate keys,
// keeping the first pair of each run; values are not inspected. If the sequence is
// sorted by key, all keys will be unique. It mirrors [Seq.Dedup], comparing keys
// with == when K is a comparable type and falling back to reflect.DeepEqual
// otherwise.
//
// Example usage:
//
// mo := g.MapOrd[g.Int, g.String]{{1, "a"}, {1, "b"}, {2, "c"}}
// mo.Iter().Dedup().Collect().MapOrd[g.Int, g.String]().Print()
//
// Output: MapOrd{1:a, 2:c}
func (seq Seq2[K, V]) Dedup() Seq2[K, V] {
eq := func(a, b K) bool { return reflect.DeepEqual(a, b) }
if isValueComparable[K]() {
eq = func(a, b K) bool { return any(a) == any(b) }
}
return func(yield func(K, V) bool) {
var prev K
first := true
seq(func(k K, v V) bool {
if first || !eq(prev, k) {
prev = k
first = false
return yield(k, v)
}
return true
})
}
}
// Unique returns a new iterator yielding only the first pair for each distinct key;
// later pairs with an already-seen key are dropped and values are not inspected.
// It mirrors [Seq.Unique]. The keys are tracked in a map, so a key type that is
// not hashable at runtime (e.g. a slice, map, function, or a struct containing
// one) panics with "hash of unhashable type".
//
// Example usage:
//
// mo := g.MapOrd[g.Int, g.String]{{1, "a"}, {2, "b"}, {1, "c"}}
// mo.Iter().Unique().Collect().MapOrd[g.Int, g.String]().Print()
//
// Output: MapOrd{1:a, 2:b}
func (seq Seq2[K, V]) Unique() Seq2[K, V] {
return func(yield func(K, V) bool) {
seen := make(map[any]struct{})
seq(func(k K, v V) bool {
key := any(k)
if _, exists := seen[key]; !exists {
seen[key] = struct{}{}
return yield(k, v)
}
return true
})
}
}
// MaxBy returns the maximum pair in the sequence using the provided comparison
// function, mirroring [Seq.MaxBy]. It returns None if the sequence is empty.
func (seq Seq2[K, V]) MaxBy(fn func(a, b Pair[K, V]) cmp.Ordering) Option[Pair[K, V]] {
var max Pair[K, V]
found := false
seq(func(k K, v V) bool {
pair := Pair[K, V]{Key: k, Value: v}
if !found || fn(max, pair) == cmp.Less {
max = pair
found = true
}
return true
})
return OptionOf(max, found)
}
// MinBy returns the minimum pair in the sequence using the provided comparison
// function, mirroring [Seq.MinBy]. It returns None if the sequence is empty.
func (seq Seq2[K, V]) MinBy(fn func(a, b Pair[K, V]) cmp.Ordering) Option[Pair[K, V]] {
var min Pair[K, V]
found := false
seq(func(k K, v V) bool {
pair := Pair[K, V]{Key: k, Value: v}
if !found || fn(pair, min) == cmp.Less {
min = pair
found = true
}
return true
})
return OptionOf(min, found)
}
// Reduce aggregates the pairs of the sequence using the provided function,
// mirroring [Seq.Reduce]. The first pair is used as the initial accumulator
// value. It returns None if the sequence is empty.
func (seq Seq2[K, V]) Reduce(fn func(a, b Pair[K, V]) Pair[K, V]) Option[Pair[K, V]] {
var acc Pair[K, V]
first := true
seq(func(k K, v V) bool {
pair := Pair[K, V]{Key: k, Value: v}
if first {
acc = pair
first = false
} else {
acc = fn(acc, pair)
}
return true
})
return OptionOf(acc, !first)
}
// Scan accumulates the pairs of the sequence using a function, yielding the
// initial value followed by each intermediate accumulator state, mirroring
// [Seq.Scan]. The accumulator type may differ from the key and value types.
//
// Example usage:
//
// mo := g.MapOrd[g.String, g.Int]{{"a", 1}, {"b", 2}, {"c", 3}}
// sums := mo.Iter().Scan(0, func(acc int, _ g.String, v g.Int) int {
// return acc + int(v)
// })
// // sums will yield: 0, 1, 3, 6
func (seq Seq2[K, V]) Scan[A any](init A, fn func(acc A, k K, v V) A) Seq[A] {
return func(yield func(A) bool) {
if !yield(init) {
return
}
acc := init
seq(func(k K, v V) bool {
acc = fn(acc, k, v)
return yield(acc)
})
}
}
// Intersperse inserts the provided separator pair between each consecutive pair
// of elements in the original iterator, mirroring [Seq.Intersperse].
func (seq Seq2[K, V]) Intersperse(sep Pair[K, V]) Seq2[K, V] {
return func(yield func(K, V) bool) {
first := true
seq(func(k K, v V) bool {
if !first && !yield(sep.Unpack()) {
return false
}
first = false
return yield(k, v)
})
}
}
// MapTo transforms each pair into a single value using the given function,
// returning a value sequence of the results. It complements [Seq2.Map], which
// keeps the pair shape.
func (seq Seq2[K, V]) MapTo[T any](fn func(K, V) T) Seq[T] {
return func(yield func(T) bool) {
seq(func(k K, v V) bool { return yield(fn(k, v)) })
}
}
// ── iterator core (key-value sequences), ported from github.com/enetx/iter (MIT) ──
// seq2Next extracts the first key-value pair from the sequence and returns the remaining sequence.
// Returns (key, value, remainingSeq, true) if a pair exists, or (zeroK, zeroV, nil, false) if empty.
//
// Example:
//
// s := Map[int, string]{1: "a", 2: "b", 3: "c"}.Iter()
// k, v, rest, ok := s.seq2Next()
// // k = 1, v = "a", ok = true (order not guaranteed for maps)
// // rest yields remaining pairs
//
// k2, v2, rest2, ok2 := rest.seq2Next()
// // k2 = 2, v2 = "b", ok2 = true
// // rest2 yields remaining pairs
func (seq Seq2[K, V]) seq2Next() (K, V, Seq2[K, V], bool) {
next, stop := seq.seq2Pull()
firstK, firstV, ok := next()
if !ok {
stop()
var zeroK K
var zeroV V
return zeroK, zeroV, nil, false
}
// The remaining sequence continues from the same pull iterator, so the source
// is walked exactly once. This makes Next O(1) per element and correct for
// non-deterministic sources (e.g. maps), at the cost of the remaining
// sequence being single-use.
remaining := func(yield func(K, V) bool) {
defer stop()
for {
k, v, ok := next()
if !ok {
return
}
if !yield(k, v) {
return
}
}
}
return firstK, firstV, remaining, true
}
// seq2Pull converts a push-style iterator (Seq2) to a pull-style iterator.
func (seq Seq2[K, V]) seq2Pull() (next func() (K, V, bool), stop func()) {
return iter.Pull2(iter.Seq2[K, V](seq))
}
// seq2ToPairs collects all key-value pairs into a slice of Pair structs.
func (seq Seq2[K, V]) seq2ToPairs() []Pair[K, V] {
out := make([]Pair[K, V], 0)
seq(func(k K, v V) bool {
out = append(out, Pair[K, V]{k, v})
return true
})
return out
}
// seqFromPairs creates a Seq2 from a slice of key-value pairs.
//
// Example:
//
// pairs := []Pair[int, string]{{1, "a"}, {2, "b"}}
// s := seqFromPairs(pairs)
func seqFromPairs[K, V any](pairs []Pair[K, V]) Seq2[K, V] {
return func(yield func(K, V) bool) {
for _, p := range pairs {
if !yield(p.Unpack()) {
return
}
}
}
}