在 golang 中的地图上执行 upsert

所以我有 2 个配置,一个你可以说它有点像默认配置,另一个基于请求需要更新或插入属性。


两者的例子:


{

    "config": {

        "type": "func1",

        "config": {

            "param1": "10",

            "param2": "10"

        },

        "connected": [

            {

                "type": "func2",

                "config": {

                    "param1": "20",

                    "param2": "20"

                },

            }

        ]

    }

}

{

    "config": {

        "type": "func1",

        "config": {},

        "connected": [

            {

                "type": "func2",

                "config": {

                    "param1": "30",

                },  

            }

        ]

    }

}


我能够遍历一个地图,但想知道如何传递两个配置/地图并检查属性是否存在。任何帮助,将不胜感激。


func checkkeyPairExists(value interface{}) {

    switch value.(type) {

    case []interface{}:

        for _, v := range value.([]interface{}) {

            checkkeyPairExists(v)

        }

    case map[string]interface{}:

        for k, v := range value.(map[string]interface{}) {

            fmt.Println(k, v)

            checkkeyPairExists(v)

        }


    }

}

所需的输出:


{

    "config": {

        "type": "func1",

        "config": {

            "param1": "10",

            "param2": "10"

        },

        "connected": [

            {

                "type": "func2",

                "config": {

                    "param1": "20",

                    "param2": "30"

                },

            }

        ]

    }

}


FFIVE
浏览 114回答 3
3回答

跃然一笑

在不了解有关您的数据/模式的安全假设的更多详细信息的情况下,很难推荐完整的解决方案,但我可以尝试一下您在此处拥有的内容。将您的概念从接口稍微限制为代表您的节点的结构可能会使这里的事情变得更容易一些。type ConfigNode struct {    Type       string    Properties map[string]string    Connected  []*ConfigNode}func (n *ConfigNode) PatchProperties(patch *ConfigNode) {    for k, v := range patch.Properties {        n.Properties[k] = v    }}func (n ConfigNode) ShallowClone() ConfigNode {    clone := ConfigNode{        Type:       n.Type,        Properties: make(map[string]string),        Connected:  make([]*ConfigNode, 0),    }    clone.PatchProperties(&n)    return clone}func (n *ConfigNode) PrintTree() string {    builder := strings.Builder{}    n.appendToTreePrint(&builder, 0)    return builder.String()}func (n *ConfigNode) appendToTreePrint(builder *strings.Builder, depth int) {    isRoot := builder == nil    tab := strings.Repeat("\t", depth)    if isRoot {        builder = &strings.Builder{}    }    builder.WriteString(tab)    builder.WriteString(n.Type)    builder.WriteRune('\n')    for k, v := range n.Properties {        builder.WriteString(fmt.Sprintf("%s - %s => %s\n", tab, k, v))    }    for _, c := range n.Connected {        c.appendToTreePrint(builder, depth+1)    }}func mergeNodes(base []*ConfigNode, patch []*ConfigNode) []*ConfigNode {    merged := make([]*ConfigNode, 0)    if patch == nil {        // No patch is being applied, just deep copy the base nodes.        for _, node := range base {            clone := node.ShallowClone()            clone.Connected = mergeNodes(clone.Connected, nil)            merged = append(merged, &clone)        }        return merged    }    baseTypes := make(map[string]*ConfigNode)    patchTypes := make(map[string]*ConfigNode)    // Key the nodes by their Type so we can match them.    for _, node := range base {        baseTypes[node.Type] = node    }    for _, node := range patch {        patchTypes[node.Type] = node    }    for k, v := range baseTypes {        mergedNode := v.ShallowClone()        if patchNode, ok := patchTypes[k]; ok {            // A patch node was found with the Type matching the base, combine the two.            mergedNode.PatchProperties(patchNode)            // Remove the patch node so we don't iterate through it later.            delete(patchTypes, k)            // Recurse in and merge child nodes.            mergedNode.Connected = mergeNodes(v.Connected, patchNode.Connected)        } else {            // There is no patch so we can just deep copy the children.            mergedNode.Connected = mergeNodes(v.Connected, nil)        }        merged = append(merged, &mergedNode)    }    // Any unmatched patch nodes can be deep copied into the output.    for _, v := range patchTypes {        mergedNode := v.ShallowClone()        mergedNode.Connected = mergeNodes(v.Connected, nil)        merged = append(merged, &mergedNode)    }    return merged}func printConfig(name string, config []*ConfigNode) {    fmt.Println(name + ":")    for _, v := range config {        fmt.Println(v.PrintTree())    }}func initTestNodes() (base []*ConfigNode, patch []*ConfigNode) {    var node1Base ConfigNode    var node2Base ConfigNode    var node3Base ConfigNode    var node1Patch ConfigNode    var node3Patch ConfigNode    var node4Patch ConfigNode    node1Base = ConfigNode{        Type: "func1",        Properties: map[string]string{            "params1": "orig1",            "params2": "orig1",        },        Connected: []*ConfigNode{&node2Base},    }    node2Base = ConfigNode{        Type: "func2",        Properties: map[string]string{            "params1": "orig2",            "params2": "orig2",        },        Connected: []*ConfigNode{&node3Base},    }    node3Base = ConfigNode{        Type: "func3",        Properties: map[string]string{            "params1": "orig3",            "params2": "orig3",        },        Connected: []*ConfigNode{},    }    node1Patch = ConfigNode{        Type: "func1",        Properties: map[string]string{            "params1": "up1",        },        Connected: []*ConfigNode{&node4Patch},    }    node3Patch = ConfigNode{        Type: "func3",        Properties: map[string]string{            "params1": "up3",        },        Connected: []*ConfigNode{},    }    node4Patch = ConfigNode{        Type: "func4",        Properties: map[string]string{            "params1": "up4",        },        Connected: []*ConfigNode{&node3Patch},    }    return []*ConfigNode{&node1Base}, []*ConfigNode{&node1Patch}}func main() {    baseConfig, patchConfig := initTestNodes()    merged := mergeNodes(baseConfig, patchConfig)    printConfig("Base Config", baseConfig)    printConfig("Patch Config", patchConfig)    printConfig("Merged Config", merged)}

繁华开满天机

递归地下降它们并更新值,因为只有properties地图内的属性才会改变。让我知道我是否可以进一步改进此功能。func checkkeyPairExists(value1, value2 interface{}) {    switch value1.(type) {    case []interface{}:        for k, v := range value1.([]interface{}) {            fmt.Println("SLICE ", k, v)            v2 := value2.([]interface{})            checkkeyPairExists(v, v2[k])        }    case map[string]interface{}:        for k, v := range value1.(map[string]interface{}) {            fmt.Println("MAP", k, v)            v2 := value2.(map[string]interface{})            if k != "config" && k != "type" && k != "connected" {                fmt.Println("UPDATED", k, v)                v2[k] = v                 continue            }            checkkeyPairExists(v, v2[k])        }    }}

MM们

你必须递归地下降他们两个:func checkkeyPairExists(value1, value2 interface{}) {    switch value1.(type) {    case []interface{}:        v2, ok:=value2.([]interface{})        if !ok {          // error, or ignore and return        }        // merge value1 and v2    case map[string]interface{}:        m2, ok:=value2.(map[string]interface{})        if !ok {            // error, or ignore and return        }        for k, v := range value1 {            if v2, exists:=m2[k]; exists {               // k exists in value2            } else {               // k is not in value2            }        }    }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go