在 Golang 中合并地图

Posted

技术标签:

【中文标题】在 Golang 中合并地图【英文标题】:Merge Maps in Golang 【发布时间】:2018-10-23 18:38:49 【问题描述】:

我需要合并多个映射 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

谢谢

【问题讨论】:

你试过什么?你遇到了什么问题?包括您的代码、您收到的输出和/或错误,以及您的预期。 另外,停止使用 Go 1.7,它甚至不再受支持。当前最新的是 1.10.2。 感谢您使用代码更新您的问题。这段代码有什么问题? 【参考方案1】:

简单合并

是的,它们可以合并,但是由于在结果映射中可能有多个值关联到同一个键,所以值类型应该是一个切片,例如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" 包含在m1m2 中,但值"val_1" 只在目标映射中与"id_1" 键关联的切片中列出一次。

【讨论】:

它不适用于切片中的重复值尝试使用github.com/fatih/set @danicheeta 是的,重复值将被列出多次。这可能是提问者想要的,也可能不是,他没有说什么。 @user3809560 是否要处理重复项?我的意思是,如果相同的"id_1": "val_1" 对包含在多个输入映射中,是否可以在"id_1": ["val_1", "val_x", "val_1"] 等目标中多次列出它?或者您想过滤掉这些重复项? @icza,您在 srcMap 中使用了 for 循环。它是什么控制结构。 1.7是否支持 @user3809560 是的,Go 1.7 支持它(但你真的应该放弃 Go 1.7 并使用 Go 1.10.2)。第二个版本有 3 个循环。最外层循环遍历输入映射的切片 (ms),第二个循环遍历输入映射 (m),最内层循环遍历结果映射的切片值以检查重复项。

以上是关于在 Golang 中合并地图的主要内容,如果未能解决你的问题,请参考以下文章

在 golang 中使用私有地图、切片的最佳实践是啥?

如何在 Go (Golang) 中检索表单数据作为地图(如 PHP 和 Ruby)

如何在 Golang 中使用接口与地图?

golang golang嵌套地图相等

golang golang flatten嵌套地图

golang golang地图列表