【问题标题】:Merge two or more []map[string]interface{} types into one in Golang在 Golang 中将两个或多个 []map[string]interface{} 类型合并为一个
【发布时间】:2017-01-16 09:58:57
【问题描述】:

我正在使用 Golang,出于某种原因,我需要合并来自不同数据库查询的结果,所有这些结果都返回给我 []map[string]interface{} 我正在考虑追加,但如果这可能的话,它还不够清楚。 我正在查看的最终数据类型是什么?

显然,键为字符串的接口映射数组应该能够简单地“附加”(连接,如果可以的话)到另一个键为字符串的接口映射数组!

那么实现这一点的机制是什么?

【问题讨论】:

  • 好吧,您可以迭代:for k, v := range(map1) { map2[k] = v},但您需要确定发生密钥冲突时会发生什么。您可以通过v, ok := map2[k]; if !ok {...} 进行检查
  • 对不起,我错过了切片。你可以做newslice := append(slice1, slice2...)blog.golang.org/slices#TOC_10
  • 如果结果类型相同,你可以只追加结果 := append(result1, result2...) []map[string]interface{}
  • 你是对的。我只是尝试了@Uvelichitel 所说的内容,并且不得不做两次(因为我有 3 个阵列),它就像一个魅力!我应该把它作为答案吗?
  • 其实问题应该重写以匹配go的语法和能力。对于 question 和 go,切片中包含地图是无关紧要的。您可以对任何切片类型执行相同操作,例如 []byte。这就是 go 的内部函数 append 的用途,也是它的文档记录方式(附加和复制切片)。

标签: arrays go types maps


【解决方案1】:

即使上面的 cmets 已经给出了答案,我也会发布一个简短的示例,如何实现这一点。

package main

import (
    "fmt"
)

func main() {
    result := []map[string]interface{}{}

    mp1 := map[string]interface{}{
        "one" : 1, 
        "two" : 2,
    }

    mp2 := map[string]interface{}{
        "three" : 3,
        "four" : 4,
    }

    mp3 := make(map[string]interface{})
    for k, v := range mp1 {
        if _, ok := mp1[k]; ok {
            mp3[k] = v          
        }
    }

    for k, v := range mp2 {
        if _, ok := mp2[k]; ok {
            mp3[k] = v
        }
    }

    result = append(result, mp1, mp2)
    fmt.Println(result)
}

输出将是:

[map[one:1 two:2] map[three:3 four:4]]

Playground example

【讨论】:

  • 赞!在我的例子中,我有 map1、map2 和 map3 所有的 []map[string]interface{} 类型,我做到了 - result := map1 result = append(result, map2...) result = append(result, map3. ..) 这正是我所需要的!
【解决方案2】:

另一个答案是正确的。您还可以编写一个辅助函数来避免重复的地图合并。

// overwriting duplicate keys, you should handle that if there is a need
func mergeMaps(maps ...map[string]interface{}) map[string]interface{} {
    result := make(map[string]interface{})
    for _, m := range maps {
        for k, v := range m {
            result[k] = v
        }
    }
    return result
}

func main() {
    log.Println(`started`)

    v := []map[string]interface{}{
        map[string]interface{}{
            `one`: 1,
            `two`: 2,
        },
        map[string]interface{}{
            `one`:   `I`,
            `three`: 3,
            `other`: `NAN`,
        },
        map[string]interface{}{
            `name`: `Bob`,
            `age`:  300,
        },
    }

    m := mergeMaps(v...)
    log.Println(m, len(m))
}

【讨论】:

  • 从长远来看是有意义且有用的!谢谢!
  • 请注意,这是一种完全不同的操作类型! append 对切片进行操作。如果合并两个映射,您可以定义两个不同的合并操作 (A := A MERGE B),其中 B[k] 覆盖 A[k],另一个其中 A[k] 在 B[k] 上保留其值。
  • 没错,这就是为什么这个答案以“另一个答案是正确的”开头的原因。虽然除了处理 json(或一些外部数据流)之外,有一个“地图切片”是一些常见的错误,并且mp3 实际上并没有在第一个答案中的任何地方使用。
  • 就个人而言,我更喜欢您的解决方案,因为在我的用例中,我实际上希望后续映射(用于存储来自多个来源的各种配置变量)覆盖存储在第一张地图。这对于这种用法完美无缺!谢谢?
  • ... 实际上,我发现了一个更有趣的建议:stackoverflow.com/a/50325337/1035977 请注意它如何依赖append() 来根据需要进行重负荷内存分配,而不是使用@987654327 @。我想这只是一个选择/偏好的问题,两者都需要垃圾收集器在最后获得一些乐趣......
【解决方案3】:

EndreKaveh 建议的上述解决方案都有效,但是当想要合并 Go 结构和映射时,使用 mergo 会更简单、方便和更优化,这涵盖了除了合并之外的大量场景地图[字符串]界面{}

package main

import (
    "fmt"
    "github.com/imdario/mergo"
)

func main() {
    mp1 := map[string]interface{}{
        "one" : 1, 
        "two" : 2,
    }

    mp2 := map[string]interface{}{
        "three" : 3,
        "four" : 4,
    }

    mergo.Merge(&mp1, mp2) //mergo.Merge(&dest,src)
   
    fmt.Println(mp1)
}

输出:

map[four:4 one:1 three:3 two:2]

附: - 在 Golang 中没有保序。实际上,在 Go 中迭代地图总是以随机顺序进行的。所以不要依赖地图的键顺序。

【讨论】:

    猜你喜欢
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    • 2015-01-14
    • 2014-04-26
    • 2011-06-21
    • 1970-01-01
    相关资源
    最近更新 更多