进行两张地图的合并


81

我有一个递归函数,用于创建表示文件路径的对象(键是路径,值是有关文件的信息)。它是递归的,因为它仅用于处理文件,因此如果遇到目录,则会在目录上递归调用该函数。

话虽这么说,我想在两个映射上做一个集合并集的等效操作(即用递归调用中的值更新“主”映射)。除了遍历一个映射并将每个键,其中的值分配给另一映射中的相同对象之外,是否有惯用的方法来做到这一点?

那就是:给定a,b的类型map [string] *SomeObject,以及ab最终被填充,有没有什么办法来更新a所有的值b


2
也许您可以使用一个实际的set容器来进行此类工作:github.com/deckarep/golang-set
Ralph Caraveo 2014年

拉尔夫的建议很适合布景。但是,我要说的是,在你的情况下,它与其说是一个联盟,因为它是一个合并; 一个集合应该只是“键”的集合,而您有两个键值对集合,其中一个“集合”应优先于另一个。
ANisus 2014年

Answers:


132

标准软件包中没有内置方法,也没有任何方法可以进行这种合并。

idomatic的方法是简单地迭代:

for k, v := range b {
    a[k] = v
}

5
要补充ANisus的回答:映射本质上是哈希表。除了简单地对两个地图进行迭代之外,没有其他方法可以更快地计算两个地图的并集。
2014年

您可能可以使用反射来编写与类型无关的联合函数,但是这样做会更慢。
伊万

在将v分配给a [k]之前,该代码难道不应该将a [k]和v的值统一吗?如果a [k]和v是数组或映射怎么办?
vdolez

2
他希望合并地图,而不一定要合并地图中的值。如果您想执行类似的操作,则只需更改a[k] = va[k] = a[k] + v或类似的操作。
凯尔(Kyle)

@凯尔我认为你是对的。对于实际的联合,可以使用:a[k] = append(a[k], v...)
user3405291

2

如果您有几个嵌套的地图,leftright,则此函数将递归地将项目从添加right到中left。如果密钥已经存在,left那么我们将更深入地探究该结构,并尝试仅密钥添加到其中left(例如,永不替换它们)。


type m = map[string]interface{}

// Given two maps, recursively merge right into left, NEVER replacing any key that already exists in left
func mergeKeys(left, right m) m {
    for key, rightVal := range right {
        if leftVal, present := left[key]; present {
            //then we don't want to replace it - recurse
            left[key] = mergeKeys(leftVal.(m), rightVal.(m))
        } else {
            // key not in left so we can just shove it in
            left[key] = rightVal
        }
    }
    return left
}

注意:我不处理值本身不是a的情况map[string]interface{}。因此,如果您有left["x"] = 1right["x"] = 2则上面的代码在尝试时会惊慌leftVal.(m)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.