Golang:对结构进行分组和求和
Posted
技术标签:
【中文标题】Golang:对结构进行分组和求和【英文标题】:Golang: group and sum slice of structs 【发布时间】:2017-02-20 13:43:45 【问题描述】:我来自 .NET 世界,在那里我拥有 LINQ,因此我可以像我们通常在 SQL 中看到的那样进行内存查询。
我有这个结构的一部分,我想按 8 个字段分组,然后对另一个整数字段求和。比如:
type Register struct
id1 int
id2 int
id3 int
id4 int
id5 int
id6 int
id7 int
id8 int
money int
我想到了:
创建一个 Equal 函数来比较结构(这八个 字段)。 遍历我正在分析的集合。对于每个项目 检查它是否已经在哈希表中。如果有 => 我总结 场。如果不是 => 我将新项目添加到哈希表中。有没有更好的方法或任何美观、高效且易于使用的方法 图书馆?
【问题讨论】:
我并没有真正理解你的问题。Equal
函数的目的是什么?我不确定您是否期待地图的地图,其中所有具有 id1 值 X
的项目都在一个组中,所有具有另一个 id1 值 Y
的项目都在不同的组等中。你能举一个输入和输出的例子吗?不需要大量数据,但足以说明您的结构不需要的点。
可以,例如:
是的,例如:[r1id1: 345, money: 1500, r2id1: 345, id2 140, money: 2700, r3id1: 345, money: 1000
。所以 r1 和 r3 应该相加得到rSummed1id: 345, money: 2500, rSummed2id1: 345, id2: 140, money: 2700
。是经典的SELECT Sum(money) GROUP BY id1, id2 ...
r2
不会也在那个组吗? id1
的值也是 345。
否,因为在 r2 中 id2 != 0。所有 id 字段必须完全相同。
【参考方案1】:
基本上你的 idXX
字段是键,一个 n 元组。而money
字段就是要求和的数据。
如果你稍微重构你的类型,这很容易做到。仅将键放入结构中,因此它可以用作映射中的键。结构体值为comparable:
如果结构值的所有字段都是可比较的,则结构值是可比较的。如果对应的非blank 字段相等,则两个结构值相等。
所以新类型:
type Key struct
id1 int
id2 int
id3 int
id4 int
id5 int
id6 int
id7 int
id8 int
type Register struct
key Key
money int
要分组和计算总和,您可以使用map[Key]int
,使用Register.key
作为映射键来“分组”具有相同键(相同ID)的所有寄存器:
regs := []*Register
Keyid1: 345, 1500,
Keyid1: 345, id2: 140, 2700,
Keyid1: 345, id2: 140, 1300,
Keyid1: 345, 1000,
Keyid3: 999, 1000,
Keyid3: 999, 2000,
// calculate sum:
m := map[Key]int
for _, v := range regs
m[v.key] += v.money
fmt.Println(m)
输出:
map[345 0 0 0 0 0 0 0:2500 345 140 0 0 0 0 0 0:4000 0 0 999 0 0 0 0 0:3000]
为了一个不错的输出:
fmt.Println("Nice output:")
for k, v := range m
fmt.Printf("%+3v: %d\n", k, v)
输出:
Nice output:
id1:345 id2: 0 id3: 0 id4: 0 id5: 0 id6: 0 id7: 0 id8: 0: 2500
id1:345 id2:140 id3: 0 id4: 0 id5: 0 id6: 0 id7: 0 id8: 0: 4000
id1: 0 id2: 0 id3:999 id4: 0 id5: 0 id6: 0 id7: 0 id8: 0: 3000
这是尽可能简单和高效的。试试Go Playground 上的示例。
注意事项:
在地图中,我们不必检查Key
是否已经在其中。这是因为如果键不在映射中,索引映射会产生映射值类型的zero value。所以在这种情况下,如果Key
还没有在地图中,m[key]
会给你0
(0
是int
类型的零值),正确地告诉你“以前”的总和到目前为止,该密钥是0
。
另请注意,Key
可能是 Register
中的 embedded field 而不是“常规”字段,这无关紧要,这样您就可以引用 idXX
字段,就好像它们是一部分一样Register
.
【讨论】:
太棒了,这正是我一直在寻找的东西。我知道有更好的方法!谢谢!!【参考方案2】:你可以试试go-linq:https://github.com/ahmetalpbalkan/go-linq/
它类似于 c# linq,在你的情况下使用 GroupBy 和 Aggregate
https://godoc.org/github.com/ahmetalpbalkan/go-linq#example-Query-GroupBy https://godoc.org/github.com/ahmetalpbalkan/go-linq#example-Query-Aggregate
伪代码:
From(regs).GroupBy(merge ids to a string as group key).Select(use Aggregate or SumInts to sum money)
【讨论】:
太棒了!似乎正是我需要的!谢谢!以上是关于Golang:对结构进行分组和求和的主要内容,如果未能解决你的问题,请参考以下文章
golang实现es根据某个字段分组,对某个字段count总数,对某个字段sum求和
golang实现es根据某个字段分组,对某个字段count总数,对某个字段sum求和
golang实现es根据某个字段分组,对某个字段count总数,对某个字段sum求和