Golang Check for existing items in slice of structs

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

Golang Check for existing items in slice of structs

问题

假设我有以下结构体:

type A struct {
    Field1 string
    Field2 string
}

type B struct {
    Field3 string
    Field4 int
}

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

type C struct {
    A
    MyList []B
}

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

var results []C

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

type X struct {
    A
    B
}

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

var results []C

// Y 是一个 X 的切片

for _, elem := range Y {
    // 如果 elem.A 已经存在,则将 elem.B 添加到 C.A 中
    // 如果不存在,则将 elem.A 和 elem.B 添加到 C 中
}

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

英文:

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

type A struct {
    Field1 string
    Field2 string
}

type B struct {
    Field3 string
    Field4 int
}

and one more struct which uses the previous two:

type C struct {
    A
    MyList []B
}

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

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):

type X struct {
    A
    B
}

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:

var results []C

// Y is an slice of Xs 

for _, elem := range Y {
    // If elem.A exists then append elem.B into C.A
    // If not then add elem.A and elem.B into C
}

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的值。

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

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

// 示例数据:
xs := []X{
	{A{"a1", "a2"}, B{"b1", 2}},
	{A{"a1", "a2"}, B{"b11", 22}},
	{A{"a1", "a3"}, B{"b4", 5}},
}
m := map[A][]B{}

for _, x := range xs {
	m[x.A] = append(m[x.A], x.B)
}

fmt.Println(m)

这将输出:

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

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

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

这将输出:

[{{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:

// Example data:
xs := []X{
	{A{"a1", "a2"}, B{"b1", 2}},
	{A{"a1", "a2"}, B{"b11", 22}},
	{A{"a1", "a3"}, B{"b4", 5}},
}
m := map[A][]B{}

for _, x := range xs {
	m[x.A] = append(m[x.A], x.B)
}

fmt.Println(m)

This will output:

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:

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

This will output:

[{{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:

确定