递归地展平地图golang

recursively flatten a map golang

使用下面的 json 我试图将其展平以便于访问。

有2个资源的例子在这个结构中可以有n个

"config": {
    "type": "r1",
    "properties": {
        "p1": "10",
        "p2": "10"
    },
    "connected": [
        {
            "type": "r3",
            "properties": {
              "p1": "10",
              "p2": "10"
            },
            "connected": [
                {}
        },
    ],
}

自定义奉承逻辑

func keyValuePairs(m interface{}) map[string]interface{} {
    kvs := make(map[string]interface{})
    if reflect.ValueOf(m).Kind() == reflect.Map {
        mp, ok := m.(map[string]interface{})
        if ok {
            var key string
            var value interface{}
            for k, v := range mp {
                switch k {
                case "type":
                    key = v.(string)
                case "properties":
                    value = v
                case "connected":
                    if collection, ok := v.([]interface{}); ok {
                        for _, c := range collection {
                            for nk, nv := range keyValuePairs(c) {
                                nnv, _ := nv.(map[string]interface{})
                                _, ok := nnv["connectedTo"]
                                if !ok {
                                   nnv["connectedTo"] = key
                                }
                                kvs[nk] = nv
                            }
                        }
                    }
                default:
                    for nk, nv := range keyValuePairs(v) {
                        kvs[nk] = nv
                    }
                }
            }
            if key != "" {
                kvs[key] = value
            }
        } else {
            for k, v := range m.(map[string]interface{}) {
                kvs[k] = v
            }
        }
    }
    return kvs
}

所需的输出有点波动,有些运行我得到了我需要的输出,有些执行“connectedTo”属性为空。

{
"r1": {
        "p1": "10",
        "p2": "10"
    },
"r3" : {
        "connectedTo": "r1",
        "p1": "10",
        "p2": "10"
    },
}

我认为处决不是按顺序进行的。不对请指正

地图上的迭代顺序是随机的。详情见Why are iterations over maps random? and

现在看看你的循环:

var key string
var value interface{}
for k, v := range mp {
    switch k {
    case "type":
        key = v.(string)
    case "properties":
        value = v
    case "connected":
        if collection, ok := v.([]interface{}); ok {
            for _, c := range collection {
                for nk, nv := range keyValuePairs(c) {
                    nnv, _ := nv.(map[string]interface{})
                    _, ok := nnv["connectedTo"]
                    if !ok {
                       nnv["connectedTo"] = key
                    }
                    kvs[nk] = nv
                }
            }
        }
    default:
        for nk, nv := range keyValuePairs(v) {
            kvs[nk] = nv
        }
    }
}

您在 "connected" 分支中使用了 key 变量,但是 "type""connected" 的顺序是 non-deterministic (随机)。

"type" 分支是设置 key 的分支,但如果先到达 "connected",则 key 将为空。

您不能依赖地图迭代顺序。

一个简单的解决方法是首先获取与"type"关联的值并将其分配给key(您在"connected"分支中使用),循环之前。

例如:

key, _ := mp["type"].(string)
value := mp["properties"]
// Now process other properties:
for k, v := range mp {
    switch k {
    case "type", "properties": // Already handled
    case "connected":
        if collection, ok := v.([]interface{}); ok {
            for _, c := range collection {
                for nk, nv := range keyValuePairs(c) {
                    nnv, _ := nv.(map[string]interface{})
                    _, ok := nnv["connectedTo"]
                    if !ok {
                       nnv["connectedTo"] = key
                    }
                    kvs[nk] = nv
                }
            }
        }
    default:
        for nk, nv := range keyValuePairs(v) {
            kvs[nk] = nv
        }
    }
}