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

Mar*_*cos 5 grouping struct dictionary go slice

我来自拥有LINQ的.NET世界,因此我可以像在SQL中通常看到的那样进行内存中查询。

我想对这个结构进行切片,然后按8个字段进行分组,然后对另一个整数字段求和。就像是:

type Register struct {
    id1 int
    id2 int
    id3 int
    id4 int
    id5 int
    id6 int
    id7 int
    id8 int
    money int
}
Run Code Online (Sandbox Code Playgroud)

我以为:

  • 创建一个Equal函数,以比较结构(那八个字
    段)。遍历我正在分析的集合。对于每个项目,
    检查它是否已经在哈希表中。如果存在=>我对字段求和。如果不是=>我将新项目添加到哈希表。

是否有更好的方法或任何美观,有效且易于使用的库?

icz*_*cza 9

基本上你的idXX字段是键,一个 n 元组。而money场要加总的数据。

如果您稍微重构您的类型,这可以轻松完成。只将键放入结构中,因此它可以用作映射中的键。结构值具有可比性

如果所有字段都具有可比性,则结构值具有可比性。如果它们对应的非空白字段相等,则两个结构值相等。

所以新类型:

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
}
Run Code Online (Sandbox Code Playgroud)

并且要分组和计算总和,您可以使用 a 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)
Run Code Online (Sandbox Code Playgroud)

输出:

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]
Run Code Online (Sandbox Code Playgroud)

对于一个不错的输出:

fmt.Println("Nice output:")
for k, v := range m {
    fmt.Printf("%+3v: %d\n", k, v)
}
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

这是尽可能简单和有效的。试试Go Playground上的例子。

笔记:

在地图中,我们不必检查 aKey是否已经在其中。这是因为如果键不在映射中,则索引映射会产生映射的值类型的零值。所以在这种情况下,如果 aKey还没有在地图中,m[key]会给你00int类型的零值),正确地告诉那个键的“前一个”总和0到目前为止。

还要注意,Key可能是一个嵌入式领域Register,而不是一个“正规”的领域,它并不重要,而这种方式,你可以参考idXX场,如果他们的一部分Register