Golang:对结构进行分组和求和
Golang: group and sum slice of structs
我来自 .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 函数,比较结构(那八个
字段)。
遍历我正在分析的集合。每一项
检查它是否已经在散列 table 中。如果它在那里 => 我求和
场。如果不是 => 我将新项目添加到散列 table.
有没有更好的方法或者有什么漂亮高效易用的方法
图书馆?
基本上你的 idXX
字段是键,一个 n 元组。而money
字段就是要求和的数据。
如果您稍微重构您的类型,这可以很容易地完成。仅将键放入结构中,因此它可以用作映射中的键。结构值为 comparable:
Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.
所以新类型:
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
作为映射键到 "group" 所有具有相同键(相同 ID)的寄存器:
regs := []*Register{
{Key{id1: 345}, 1500},
{Key{id1: 345, id2: 140}, 2700},
{Key{id1: 345, id2: 140}, 1300},
{Key{id1: 345}, 1000},
{Key{id3: 999}, 1000},
{Key{id3: 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
类型的零值) ,正确地说明该键的 "previous" 总和到目前为止是 0
。
另请注意,Key
可能是 Register
中的 embedded field 而不是 "regular" 字段,没关系,这样你可以参考idXX
字段就好像它们是 Register
.
的一部分一样
你可以试试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)
我来自 .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 函数,比较结构(那八个
字段)。 遍历我正在分析的集合。每一项
检查它是否已经在散列 table 中。如果它在那里 => 我求和 场。如果不是 => 我将新项目添加到散列 table.
有没有更好的方法或者有什么漂亮高效易用的方法 图书馆?
基本上你的 idXX
字段是键,一个 n 元组。而money
字段就是要求和的数据。
如果您稍微重构您的类型,这可以很容易地完成。仅将键放入结构中,因此它可以用作映射中的键。结构值为 comparable:
Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.
所以新类型:
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
作为映射键到 "group" 所有具有相同键(相同 ID)的寄存器:
regs := []*Register{
{Key{id1: 345}, 1500},
{Key{id1: 345, id2: 140}, 2700},
{Key{id1: 345, id2: 140}, 1300},
{Key{id1: 345}, 1000},
{Key{id3: 999}, 1000},
{Key{id3: 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
类型的零值) ,正确地说明该键的 "previous" 总和到目前为止是 0
。
另请注意,Key
可能是 Register
中的 embedded field 而不是 "regular" 字段,没关系,这样你可以参考idXX
字段就好像它们是 Register
.
你可以试试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)