go - 在 Go 中实现聚合的最佳方式(如 SQL 中的 GROUP BY)?
问题描述
假设我有一个结构
type row struct {
f1, f2, f3 string
v int64
}
我们可以把它想象成表格中的一行。
另外,我需要实现一个像这个查询一样进行聚合的函数:
SELECT f1, f2, f3, SUM(v) FROM table GROUP BY f1, f2, f3
所以,我必须实现功能:
type key struct {
f1, f2, f3 string
}
func aggregate(t []row) map[key]int64
或者如果可以
func aggregate(t []row) map[string]row
例如,其中映射键是 f1+f2+f3
func aggregate(t []row) []row
如果结果将包含唯一的 f1、f2、f3 组合(DISTINCT f1、f2、f3),也可以使用
我有两种变体:
func aggregate1(t []row) map[key]int64 {
res := map[key]int64{}
for _, r := range t {
res[key{r.f1, r.f2, r.f3}] += r.v
}
return res
}
func aggregate2(t []row) map[string]*row {
res := map[string]*row{}
for _, r := range t {
var sb strings.Builder
sb.WriteString(r.f1)
sb.WriteString("#")
sb.WriteString(r.f2)
sb.WriteString("#")
sb.WriteString(r.f3)
id := sb.String()
t := res[id]
if t == nil {
t = &row{f1: r.f1, f2: r.f2, f3: r.f3, v: 0}
res[id] = t
}
t.v += r.v
}
return res
}
第一个变种在https://golang.org/pkg/runtime/?m=all#mapassign (runtime.mapassign)中花费了太多时间
第二种变体的想法是使用更快的https://golang.org/pkg/runtime/?m=all#mapassign_faststr (runtime.mapassign_faststr),但是 strings.Builder.WriteString 消除了 runtime.mapassign_faststr 的所有好处 :(
那么,您能否提出更多关于如何实现此聚合的想法?
我正在考虑如何有效地计算第二个变体中的“id”。它应该是独一无二的。我的变体是独一无二的,因为 f1、f2 和 f3 不能包含“#”字符。
解决方案
推荐阅读
- jenkins - 如何为上传到 Jfrog Artifactory 的每个工件触发 Jenkins 管道构建
- apache - 在 Apache 上设置 ProxyPass 时,如何保留“位置”行?
- r - 在 R 包 FactoExtra 的 fviz_pca 中指定颜色和形状图例
- php - 在会话中保存下拉菜单中的数据并显示在另一个页面 Codeigniter
- google-chrome - 是否可以创建一个 chrome 扩展来在重定向之前拦截浏览器搜索栏中的用户类型?
- azure - 如何创建 Azure SQL 数据库的端点以从 API 访问
- vscode-extensions - 在 VS Code 中,如何为不受支持的语言创建自定义“转到定义”功能?
- c - Else 语句总是运行
- python - ValueError:数据基数不明确:x 大小:3 y 大小:13 确保所有数组包含相同数量的样本
- ruby-on-rails - 试图了解关系表的迁移顺序