ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

lo 的 it.Mean / it.MeanBy:基于 Go 1.23 iter.Seq 的流式均值聚合实战指南

lo 的 it.Mean / it.MeanBy:基于 Go 1.23 iter.Seq 的流式均值聚合实战指南 lo 的 it.Mean / it.MeanBy基于 Go 1.23 iter.Seq 的流式均值聚合实战指南【免费下载链接】lo A Lodash-style Go library based on Go 1.18 Generics (map, filter, contains, find...)项目地址: https://gitcode.com/GitHub_Trending/lo/lo导读本文围绕 docs/data/it-mean.md 讲解的it.Mean与it.MeanBy展开它们是 lo 项目中it包iterator 版本的核心数学聚合工具前者直接计算一个迭代序列的算术平均值后者允许在求均值前先对每个元素做一次变换。读完本文你将掌握两个函数的完整签名、空序列与整数截断等边界语义、单遍扫描的底层实现原理以及它们与 core 包切片版Mean/MeanBy/MeanByErr的差异可直接在自己的 Go 1.23 项目中落地使用。一、函数定位it包与iter.Seq流式编程lo 的it子包it/math.go与 core 包math.go提供同名数学聚合函数区别在于输入形态core 包面向[]T切片一次性持有全部数据it包面向iter.Seq[T]序列即 Go 1.23 标准库iter包引入的迭代器数据可惰性产生、边遍历边聚合。因此it包源码文件首行带有//go:build go1.23构建约束见 it/math.go使用前需确认go.mod中的 Go 版本不低于 1.23且go指令为go 1.23或更高。二、函数签名与类型约束根据 docs/data/it-mean.md 的 frontmatter两个函数签名如下func MeanT constraints.Float | constraints.Integer T func MeanByT any, R constraints.Float | constraints.Integer R) R要点Mean的输入元素类型T必须是有序数值类型浮点或整数MeanBy的输入T可以是任意类型只需通过iteratee func(item T) R变换出数值R后再求均值约束constraints.Float/constraints.Integer定义在 internal/constraints/constraints.goFloat覆盖~float32 | ~float64Integer覆盖Signed | Unsigned即~int、~int8、~int16、~int32、~int64与~uint、~uint8、~uint16、~uint32、~uint64、~uintptr。注意约束都带~波浪号因此自定义的底层类型如type Score float64同样可以直接使用。三、行为语义文档明确了两条核心语义计算算术平均值arithmetic mean即总和除以元素个数空序列返回零值 0不会出现除零或 panic。MeanBy则先变换、后求均值每个元素先经iteratee映射为数值R再对这些R求均值。文档示例 1Mean与整数除法avg : it.Mean(iter.Seqint bool){ _ y(2); _ y(3); _ y(5) })) // avg 10/3 3 (int division)三个整数求和为 10元素个数为 3。因为T int10 / 3按 Go 整数除法向下截断得到3浮点意义上的3.333…不会出现。文档示例 2MeanBy变换后求均值avg : it.MeanBy(iter.Seqstring bool){ _ y(aa); _ y(bbb) }), func(s string) int { return len(s) }) // (23)/2 2这里输入是字符串序列iteratee取每个字符串的长度len(aa) 2、len(bbb) 3均值为(23)/2 2整数截断。这展示了MeanBy的典型用法——把任意类型先投影为数值再做聚合。四、源码实现剖析单遍扫描的sum / length两个函数的实现位于 it/math.go// Mean calculates the mean of a collection of numbers. // Will iterate through the entire sequence. // Play: https://go.dev/play/p/Lez0CsvVRl_l func MeanT constraints.Float | constraints.Integer 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. // Play: https://go.dev/play/p/Ked4rpztH5Y func MeanByT any, R constraints.Float | constraints.Integer R) R { var sum R var length R for item : range collection { sum transform(item) length } if length 0 { return 0 } return sum / length }实现细节值得注意Mean委托MeanByMean只是把恒等变换func(item T) T { return item }传给MeanBy两份逻辑天然保持一致避免重复实现单遍惰性扫描for item : range collection直接消费iter.Seq[T]序列在遍历过程中惰性产出无需物化成完整切片内存占用与序列长度无关和与长度均以R累积sum与length都声明为结果类型R最终sum / length直接做类型一致的除法。这也解释了整数场景下的截断行为——除法发生在R类型内空序列保护先检查length 0返回0避免除以零。五、与 core 包切片版Mean/MeanBy/MeanByErr的对比it包并不是孤立的core 包在 math.go 中提供了切片版的同族函数可以对照理解设计意图func MeanT constraints.Float | constraints.Integer T { length : T(len(collection)) if length 0 { return 0 } sum : Sum(collection) return sum / length } func MeanByT any, R constraints.Float | constraints.Integer R) R { length : R(len(collection)) if length 0 { return 0 } sum : SumBy(collection, iteratee) return sum / length }差异与联系维度core 切片版math.goit 序列版it/math.go输入[]Titer.Seq[T]空集合返回值00长度获取直接len(collection)O(1)遍历中length累计需走完整个序列求和实现复用Sum/SumBy内联在单遍循环中Go 版本要求Go 1.18 泛型即可需 Go 1.23iter包此外 core 包还提供带错误传播的MeanByErrmath.goiteratee返回(R, error)遇到错误立即停止迭代并返回错误空切片时返回(0, nil)——it序列版目前没有对应变体需要在错误场景下自行处理或使用 core 包。六、测试与可运行示例验证仓库为两个函数提供了完整的测试与 Example 用例可作为行为契约的直接依据。单元测试it/math_test.go 中的TestMean/TestMeanBy覆盖了多种数值类型float32Mean(valuesfloat32)期望值3.725用is.InEpsilon(3.725, result, 1e-7)做浮点容差断言验证浮点结果而非精确相等int32Mean(valuesint32)期望int32(3)整数截断uint32表格驱动测试同时覆盖非空{2,3,4,5}→3与空{}→0两种输入。测试中的values辅助函数定义在 it/lo_test.gofunc valuesT any iter.Seq[T] { return slices.Values(v) }即用slices.Values把变长参数包装成iter.Seq。Example 用例it/math_example_test.go 给出了可直接复制运行的规范示例func ExampleMean() { ints : slices.Values([]int{1, 2, 3, 4, 5}) result : Mean(ints) fmt.Printf(%v, result) // Output: 3 } func ExampleMeanBy() { strs : slices.Values([]string{foo, bar}) result : MeanBy(strs, func(item string) int { return len(item) }) fmt.Printf(%v, result) // Output: 3 }注意Example注释中的// Output:会被go test自动比对因此这两个用例本身就是经过测试验证的输出断言{1,2,3,4,5}的均值为3{foo,bar}按长度投影后的均值(33)/2同样为3。七、实战注意点综合文档、源码与测试使用it.Mean/it.MeanBy时有几个容易踩坑的地方整数截断是类型行为不是 bug当R为整数类型时sum / length向下取整。若需要精确的小数均值请显式指定浮点类型例如把变换结果转为float64avg : it.MeanBy(ints, func(n int) float64 { return float64(n) })空序列返回 0请与业务上的无数据语义区分函数层面无法区分均值确实是 0与序列为空需要业务侧自行判断序列是否为空如先it.IsEmpty或保留长度信息。浮点结果用容差断言参考测试中的is.InEpsilon(3.725, result, 1e-7)浮点均值不要用精确比较。Mean会完整遍历序列源码注释明确写着 Will iterate through the entire sequence对无限序列调用会永不返回务必只在有限序列上使用同时由于iter.Seq的惰性配合Range、RangeFrom、RangeWithSteps见 it/math.go等生成器函数可以做到边生成边聚合无需先构造完整切片。MeanBy适合先投影再聚合例如按结构体字段、字符串长度、自定义评分等维度求平均输入T完全不受数值约束限制。八、延伸阅读完整函数文档docs/data/it-mean.md、core 版 docs/data/core-mean.mdit包数学函数分类索引docs/docs/iter/math.md同族聚合函数源码Sum/SumByit/math.go、Product/ProductByit/math.go、Modeit/math.gocore 切片版完整实现math.go【免费下载链接】lo A Lodash-style Go library based on Go 1.18 Generics (map, filter, contains, find...)项目地址: https://gitcode.com/GitHub_Trending/lo/lo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表