Golang Check for existing items in slice of structs

huangapple go评论181阅读模式
英文:

Golang Check for existing items in slice of structs

问题

假设我有以下结构体:

  1. type A struct {
  2. Field1 string
  3. Field2 string
  4. }
  5. type B struct {
  6. Field3 string
  7. Field4 int
  8. }

还有一个使用前两个结构体的结构体:

  1. type C struct {
  2. A
  3. MyList []B
  4. }

现在,我有一些数据,我想将其分组并映射到一个 C 结构体中,并返回一个 C 的切片:

  1. var results []C

我有一个结构体切片,看起来像这样(由于它是一个切片,可能会有重复的 A):

  1. type X struct {
  2. A
  3. B
  4. }

所以我想按 A 进行分组。为此,我将遍历一个作为参数传递给我的方法的 X 结构体切片:

  1. var results []C
  2. // Y 是一个 X 的切片
  3. for _, elem := range Y {
  4. // 如果 elem.A 已经存在,则将 elem.B 添加到 C.A 中
  5. // 如果不存在,则将 elem.A 和 elem.B 添加到 C 中
  6. }

如何实现上述注释中的内容?也就是说,我如何检查结构体 A 是否已经存在于结构体切片 C 中?

英文:

Let's say I've got the following structs:

  1. type A struct {
  2. Field1 string
  3. Field2 string
  4. }
  5. type B struct {
  6. Field3 string
  7. Field4 int
  8. }

and one more struct which uses the previous two:

  1. type C struct {
  2. A
  3. MyList []B
  4. }

Now, I've got some data that I want to group and map into a C struct and return a slice of C:

  1. var results []C

I've got a slice of structs that looks like (since it's a slice if could happen that we have repeated A):

  1. type X struct {
  2. A
  3. B
  4. }

So I want to group the results by A. To do so I'm gonna iterate through a slice of X that my method receive as parameter:

  1. var results []C
  2. // Y is an slice of Xs
  3. for _, elem := range Y {
  4. // If elem.A exists then append elem.B into C.A
  5. // If not then add elem.A and elem.B into C
  6. }

How can achieve the stuff stated in the comments above? I mean, how could I check if a struct A exists already in the slice of structs C?

答案1

得分: 3

通常,当你想按某个值进行聚合时,你会使用一个映射(map)。键将是你想要按其聚合的值,在你的情况下是类型为A的值。

在这里也是最简单的方法,只需要键的类型是可比较的。

你可以像这样简单地收集数据:

  1. // 示例数据:
  2. xs := []X{
  3. {A{"a1", "a2"}, B{"b1", 2}},
  4. {A{"a1", "a2"}, B{"b11", 22}},
  5. {A{"a1", "a3"}, B{"b4", 5}},
  6. }
  7. m := map[A][]B{}
  8. for _, x := range xs {
  9. m[x.A] = append(m[x.A], x.B)
  10. }
  11. fmt.Println(m)

这将输出:

  1. map[{a1 a2}:[{b1 2} {b11 22}] {a1 a3}:[{b4 5}]]

如果你确实需要将结果作为[]C,可以遍历映射并填充它:

  1. for a, bs := range m {
  2. results = append(results, C{a, bs})
  3. }
  4. fmt.Println(results)

这将输出:

  1. [{{a1 a2} [{b1 2} {b11 22}]} {{a1 a3} [{b4 5}]}]

你可以在Go Playground上尝试这些示例。

如果不巧的是,A不可比较,你将不得不使用循环而不是映射查找,你需要手动检查是否相等,如果找到匹配项,执行追加操作。

英文:

Usually when you want to aggregate something by some value, you use a map. The key will be the value you want to aggregate by, type of A in your case.

This is easiest here too, this only requires the key type to be comparable.

You may simply gather the data like this:

  1. // Example data:
  2. xs := []X{
  3. {A{"a1", "a2"}, B{"b1", 2}},
  4. {A{"a1", "a2"}, B{"b11", 22}},
  5. {A{"a1", "a3"}, B{"b4", 5}},
  6. }
  7. m := map[A][]B{}
  8. for _, x := range xs {
  9. m[x.A] = append(m[x.A], x.B)
  10. }
  11. fmt.Println(m)

This will output:

  1. map[{a1 a2}:[{b1 2} {b11 22}] {a1 a3}:[{b4 5}]]

If you do need the result as []C, iterate over the map and populate it:

  1. for a, bs := range m {
  2. results = append(results, C{a, bs})
  3. }
  4. fmt.Println(results)

This will output:

  1. [{{a1 a2} [{b1 2} {b11 22}]} {{a1 a3} [{b4 5}]}]

Try the examples on the Go Playground.

If by any chance A wouldn't be comparable, you would have to resort to using loops instead of map lookups where you would have to manually check for equivalence, and if you find a match, you'd perform the append operation.

huangapple
  • 本文由 发表于 2022年1月3日 04:24:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/70559498.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定