简体   繁体   English

Golang 深度合并两张地图

[英]Golang merge deeply two maps

I'm trying to deep copy of two yaml, trying to simulate the behaviour that use helm when you pass multiple values during an installation.我正在尝试对两个 yaml 进行深度复制,试图模拟在安装过程中传递多个值时使用helm的行为。 Because of a project restriction, I'm getting the values from strings and not directly form yamls.由于项目限制,我从字符串中获取值,而不是直接形成 yaml。 The problem is that the copy is not done as I expect.问题是复制没有按照我的预期完成。

I add an example:我添加一个例子:

value1 :值 1

test:
  somekey: 1
  otherkey: 2
othertest:
  somekey: 3

value2 :值 2

test:
  somekey: NEWVALUE1
  NEWKEY: NEWVALUE2

EXPECTED OUTPUT :预计 OUTPUT

test:
  somekey: NEWVALUE1
  otherkey: 2
  NEWKEY: NEWVALUE2
othertest:
  somekey: 3

RESULT :结果

othertest:
  somekey: 3
test:
  NEWKEY: NEWVALUE2
  somekey: NEWVALUE1

So as you can see in the example, it is overwritting all the test map, when I would like to merge both test maps.因此,正如您在示例中看到的,当我想合并两个test图时,它覆盖了所有test map。

Here I add the code I'm using在这里我添加我正在使用的代码

package main

import (
    "github.com/prometheus/common/log"
    "gopkg.in/yaml.v2"
)

func main() {
    value1 := "test:\n  somekey: 1\n  otherkey: 2\nothertest:\n  somekey: 3"
    value2 := "test:\n  somekey: NEWVALUE1\n  NEWKEY: NEWVALUE2"
    values := []string{value1, value2}
    result, err := getValuesFromString(values)
    if err != nil {
        log.Info(err)
    }

    //expecting: test:\n  somekey: NEWVALUE1\n  otherkey: 2\n  NEWKEY: NEWVALUE2\nothertest:\n  somekey: 3
    //getting: othertest:\n  somekey: 3\ntest:\n  NEWKEY: NEWVALUE2\n  somekey: NEWVALUE1\n
    log.Info("FINAL VALUES: " + result)
}

func getValuesFromString(values []string) (string, error) {

    var resultValues map[string]interface{}
    var bs []byte
    for _, value := range values {
        log.Info(values)
        var override map[string]interface{}
        bs = []byte(value)

        if err := yaml.Unmarshal(bs, &override); err != nil {
            log.Info(err)
            continue
        }

        //check if is nil. This will only happen for the first value
        if resultValues == nil {
            resultValues = override
        } else {
            resultValues = mergeMaps(resultValues, override)
        }
    }

    bs, err := yaml.Marshal(resultValues)
    if err != nil {
        log.Info(err)
        return "", err
    }

    return string(bs), nil
}

func mergeMaps(a, b map[string]interface{}) map[string]interface{} {
    out := make(map[string]interface{}, len(a))
    for k, v := range a {
        out[k] = v
    }
    for k, v := range b {
        if v, ok := v.(map[string]interface{}); ok {
            if bv, ok := out[k]; ok {
                if bv, ok := bv.(map[string]interface{}); ok {
                    out[k] = mergeMaps(bv, v)
                    continue
                }
            }
        }
        out[k] = v
    }
    return out
}

I think the error is that I'm generating incorrectly the map from the string var resultValues map[string]interface{} , but I didn't find the way to convert the string to a map我认为错误是我从字符串var resultValues map[string]interface{}错误地生成了 map ,但我没有找到将字符串转换为 map 的方法

Use map[interface{}]interface{} instead of map[string]interface{} .使用map[interface{}]interface{}而不是map[string]interface{} You could have a deeper look at yaml.Unmarshal .您可以更深入地了解yaml.Unmarshal

func mergeMaps(a, b map[interface{}]interface{}) map[interface{}]interface{} {
    out := make(map[interface{}]interface{}, len(a))
    for k, v := range a {
        out[k] = v
    }
    for k, v := range b {
        // If you use map[string]interface{}, ok is always false here.
        // Because yaml.Unmarshal will give you map[interface{}]interface{}.
        if v, ok := v.(map[interface{}]interface{}); ok {
            if bv, ok := out[k]; ok {
                if bv, ok := bv.(map[interface{}]interface{}); ok {
                    out[k] = mergeMaps(bv, v)
                    continue
                }
            }
        }
        out[k] = v
    }
    return out
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM