Files
lo/it/math.go
T
Nathan Baulch 43cef1f439 feat: new iter package (#672)
* lint: pin golangci-lint version

* lint: fix issues triggered by go1.23 upgrade

* feat: new iter package

* lint: fix linter issues

* fix: restore go1.18

* fix: rename package to "it"

* feat: assign multiple sequences of maps

* fix: panic in DropRight if n = 0

* docs: fix incorrect non-iter helper references

* feat: implement Invert helper

* feat: helpers for creating and checking empty sequences

* feat: implement Reverse helper

* feat: implement ReduceRight helper

* feat: implement Shuffle helper

* feat: implement Sample* helpers

* refactor: rename helpers with Seq convention

* feat: implement SeqToChannel2 helper

* feat: implement HasPrefix/HasSuffix helpers

* chore: port recent changes

* perf: only iterate collection once in Every

* refactor: reduce dupe code by reusing helpers internally

* perf: reuse internal Mode slice

* feat: implement Length helper

* chore: duplicate unit tests for *I helpers

* fix: omit duplicates in second Intersect list

* feat: intersect more than 2 sequences

* feat: implement Drain helper

* feat: implement Seq/Seq2 conversion helpers

* refactor: rename *Right* to *Last*

* chore: minor cleanup

* refactor: consistent predicate/transform parameter names

* perf: abort Slice/Subset once upper bound reached

* refactor: rename IsSortedByKey to IsSortedBy

* refactor: reuse more helpers internally

* feat: implement Cut* helpers

* feat: implement Trim* helpers

* perf: reduce allocations

* docs: describe iteration and allocation expectations

* Update .github/workflows/lint.yml

---------

Co-authored-by: Samuel Berthe <dev@samuel-berthe.fr>
2025-10-02 19:23:16 +02:00

143 lines
4.3 KiB
Go

//go:build go1.23
package it
import (
"iter"
"github.com/samber/lo"
"github.com/samber/lo/internal/constraints"
)
// Range creates a sequence of numbers (positive and/or negative) with given length.
func Range(elementNum int) iter.Seq[int] {
length := lo.If(elementNum < 0, -elementNum).Else(elementNum)
step := lo.If(elementNum < 0, -1).Else(1)
return func(yield func(int) bool) {
for i, j := 0, 0; i < length; i, j = i+1, j+step {
if !yield(j) {
return
}
}
}
}
// RangeFrom creates a sequence of numbers from start with specified length.
func RangeFrom[T constraints.Integer | constraints.Float](start T, elementNum int) iter.Seq[T] {
length := lo.If(elementNum < 0, -elementNum).Else(elementNum)
step := lo.If(elementNum < 0, -1).Else(1)
return func(yield func(T) bool) {
for i, j := 0, start; i < length; i, j = i+1, j+T(step) {
if !yield(j) {
return
}
}
}
}
// RangeWithSteps creates a sequence of numbers (positive and/or negative) progressing from start up to, but not including end.
// step set to zero will return an empty sequence.
func RangeWithSteps[T constraints.Integer | constraints.Float](start, end, step T) iter.Seq[T] {
return func(yield func(T) bool) {
if start == end || step == 0 {
return
}
if start < end {
if step < 0 {
return
}
for i := start; i < end; i += step {
if !yield(i) {
return
}
}
}
if step > 0 {
return
}
for i := start; i > end; i += step {
if !yield(i) {
return
}
}
}
}
// Sum sums the values in a collection. If collection is empty 0 is returned.
// Will iterate through the entire sequence.
func Sum[T constraints.Float | constraints.Integer | constraints.Complex](collection iter.Seq[T]) T {
return SumBy(collection, func(item T) T { return item })
}
// SumBy summarizes the values in a collection using the given return value from the iteration function. If collection is empty 0 is returned.
// Will iterate through the entire sequence.
func SumBy[T any, R constraints.Float | constraints.Integer | constraints.Complex](collection iter.Seq[T], transform func(item T) R) R {
var sum R
for item := range collection {
sum += transform(item)
}
return sum
}
// Product gets the product of the values in a collection. If collection is empty 1 is returned.
// Will iterate through the entire sequence.
func Product[T constraints.Float | constraints.Integer | constraints.Complex](collection iter.Seq[T]) T {
return ProductBy(collection, func(item T) T { return item })
}
// ProductBy summarizes the values in a collection using the given return value from the iteration function. If collection is empty 1 is returned.
// Will iterate through the entire sequence.
func ProductBy[T any, R constraints.Float | constraints.Integer | constraints.Complex](collection iter.Seq[T], transform func(item T) R) R {
var product R = 1
for item := range collection {
product *= transform(item)
}
return product
}
// Mean calculates the mean of a collection of numbers.
// Will iterate through the entire sequence.
func Mean[T constraints.Float | constraints.Integer](collection iter.Seq[T]) T {
return MeanBy(collection, func(item T) T { return item })
}
// MeanBy calculates the mean of a collection of numbers using the given return value from the iteration function.
// Will iterate through the entire sequence.
func MeanBy[T any, R constraints.Float | constraints.Integer](collection iter.Seq[T], transform func(item T) R) R {
var sum R
var length R
for item := range collection {
sum += transform(item)
length++
}
if length == 0 {
return 0
}
return sum / length
}
// Mode returns the mode (most frequent value) of a collection.
// If multiple values have the same highest frequency, then multiple values are returned.
// If the collection is empty, then the zero value of T is returned.
// Will iterate through the entire sequence and allocate a map large enough to hold all distinct elements.
// Long heterogeneous input sequences can cause excessive memory usage.
func Mode[T constraints.Integer | constraints.Float](collection iter.Seq[T]) []T {
var mode []T
maxFreq := 0
frequency := make(map[T]int)
for item := range collection {
frequency[item]++
count := frequency[item]
if count > maxFreq {
maxFreq = count
mode = append(mode[:0], item)
} else if count == maxFreq {
mode = append(mode, item)
}
}
return mode
}