在 Golang 中合并地图

use*_*560 4 merge dictionary go slice

I need to merge multiple maps map1 = [ id: id_1 val: val_1 ], map2 = [ id: id_2 val: val_2 ] and map3 = [id: id_1, val: val_3] such that the result map should be merged on the id values:

result_map = [id: id_1 val: {val_1, val_3}, id: id_2 var: {val_2}} ]
Run Code Online (Sandbox Code Playgroud)

The code I've tried:

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

Is there a way this can be done? Am using Golang 1.7

Thanks

icz*_*cza 9

简单合并

是的,它们可以合并,但是由于在结果映射中可能有多个值关联到同一个键,值类型应该是一个切片,例如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
}
Run Code Online (Sandbox Code Playgroud)

这个merge()函数有一个可变参数,这意味着你可以向它传递任意数量的映射。

请注意,您不需要初始化目标映射中的切片,因为使用尚未在其中的键索引映射将导致其类型的零值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)
Run Code Online (Sandbox Code Playgroud)

输出(在Go Playground上试试):

map[id_1:[val_1 val_3] id_2:[val_2]]
Run Code Online (Sandbox Code Playgroud)

避免重复

请注意,以上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
}
Run Code Online (Sandbox Code Playgroud)

测试它:

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

输出(在Go Playground上试试):

map[id_1:[val_1 val_3] id_2:[val_2]]
Run Code Online (Sandbox Code Playgroud)

我们可以看到它"id_1": "val_1"同时包含在m1和 中m2,但该值"val_1""id_1"在与目标映射中的键关联的切片中列出一次。