简单合并
是的,它们可以合并,但是由于在结果映射中可能有多个值关联到同一个键,所以值类型应该是一个切片,例如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(切片为 nil ),并且您可以附加到 nil 切片,内置的 append() 函数负责(重新)分配。
测试它:
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)
输出(在Go Playground上试试):
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
}
测试它:
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)
输出(在Go Playground上试试):
map[id_1:[val_1 val_3] id_2:[val_2]]
我们可以看到"id_1": "val_1" 包含在m1 和m2 中,但值"val_1" 只在目标映射中与"id_1" 键关联的切片中列出一次。