为了账号安全,请及时绑定邮箱和手机立即绑定

在 golang 中的地图上执行 upsert

在 golang 中的地图上执行 upsert

Go
FFIVE 2022-12-19 10:38:21
所以我有 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"                },            }        ]    }}
查看完整描述

3 回答

?
跃然一笑

TA贡献1826条经验 获得超6个赞

在不了解有关您的数据/模式的安全假设的更多详细信息的情况下,很难推荐完整的解决方案,但我可以尝试一下您在此处拥有的内容。


将您的概念从接口稍微限制为代表您的节点的结构可能会使这里的事情变得更容易一些。


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)

}



查看完整回答
反对 回复 2022-12-19
?
繁华开满天机

TA贡献1816条经验 获得超4个赞

递归地下降它们并更新值,因为只有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])

        }


    }

}


查看完整回答
反对 回复 2022-12-19
?
MM们

TA贡献1886条经验 获得超2个赞

你必须递归地下降他们两个:


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

            }

        }


    }

}


查看完整回答
反对 回复 2022-12-19
  • 3 回答
  • 0 关注
  • 113 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号