Golang:对结构进行分组和求和

时间:2016-10-11 21:26:13

标签: dictionary go struct grouping slice

我来自.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
}

我想:

  • 创建一个等于函数,来比较结构(那八个 字段)。 迭代我正在分析的集合。对于每个项目
    检查它是否已经在哈希表中。如果它在那里=>我总结 场。如果不是=>我将新项添加到哈希表。

是否有更好的方式或任何美观,高效和易于使用 库中?

2 个答案:

答案 0 :(得分:4)

基本上你的idXX字段是键,一个n元组。 money字段是要求和的数据。

如果您稍微重构一下类型,就可以轻松完成。只将键放入结构中,因此它可以用作地图中的键。结构值为comparable

  

如果所有字段都具有可比性,则结构值具有可比性。如果相应的非blank字段相等,则两个struct值相等。

所以新类型:

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{
    {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]将为您提供00int类型的零值) ,正确地告诉"之前"到目前为止,该密钥的总和为0

另请注意,Key可能是Register中的embedded field而不是"常规"}字段,它并不重要,这样您可以引用idXX字段,就好像它们是Register的一部分一样。

答案 1 :(得分:0)

您可以尝试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)