mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-10-04 14:36:50 +02:00
1153 lines
30 KiB
Go
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
|
|
}
|
|
}
|
|
}
|
|
}
|