我需要合并多个地图map1 = [ id: id_1 val: val_1 ]
,map2 = [ id: id_2 val: val_2 ]
和map3 = [id: id_1, val: val_3]
,以便结果地图应合并到id
值:
result_map = [id: id_1 val: {val_1, val_3}, id: id_2 var: {val_2}} ]
我试过的代码:
var a = make(map[string]interface{})
for _, m := range data {
for _, n := range data {
if m["id"] == n["id"] {
for l, k := range n {
c[l] = k
}
}
}
}
有没有办法可以做到这一点?我正在使用Golang 1.7
由于
答案 0 :(得分:4)
是的,它们可以合并,但由于在结果映射中可能存在与同一个键关联的多个值,因此值类型应为切片,例如map[string][]string
。
要进行合并,只需对要合并的地图进行范围调整,然后将源地图中的每个值附加到与结果地图中相同关键字相关联的切片。
要注意的一点是,一旦执行追加,就必须将结果切片分配回结果映射中的相同键。
这是一个简单的实现:
func merge(ms ...map[string]string) map[string][]string {
res := map[string][]string{}
for _, m := range ms {
for k, v := range m {
res[k] = append(res[k], v)
}
}
return res
}
此merge()
函数具有可变参数,这意味着您可以向其传递任意数量的映射。
请注意,您不需要初始化目标地图中的切片,因为使用尚未包含其中的键索引地图将导致其类型的zero value({{1}对于切片而言,您可以附加到nil
切片,内置append()
函数负责(重新)分配。
测试它:
nil
输出(在Go Playground上尝试):
m1 := map[string]string{"id_1": "val_1"}
m2 := map[string]string{"id_2": "val_2"}
m3 := map[string]string{"id_1": "val_3"}
res := merge(m1, m2, m3)
fmt.Println(res)
请注意,上述map[id_1:[val_1 val_3] id_2:[val_2]]
不会过滤掉重复项,这意味着如果多个输入映射中包含相同的merge()
对,它将在目标中多次列出,如"id_1": "val_1"
。要过滤掉这样的副本(只在目标中列出一次),我们必须在执行追加之前检查一下(如果我们之前遇到过,请跳过追加)。
这是如何做到的:
"id_1": ["val_1", "val_1", "val_x"]
测试它:
func merge(ms ...map[string]string) map[string][]string {
res := map[string][]string{}
for _, m := range ms {
srcMap:
for k, v := range m {
// Check if (k,v) was added before:
for _, v2 := range res[k] {
if v == v2 {
continue srcMap
}
}
res[k] = append(res[k], v)
}
}
return res
}
输出(在Go Playground上尝试):
m1 := map[string]string{"id_1": "val_1"}
m2 := map[string]string{"id_2": "val_2", "id_1": "val_1"}
m3 := map[string]string{"id_1": "val_3"}
res := merge(m1, m2, m3)
fmt.Println(res)
我们可以看到map[id_1:[val_1 val_3] id_2:[val_2]]
和"id_1": "val_1"
中都包含m1
,但m2
值只列在与{{1}相关联的切片中键入目标地图。