【问题标题】:How to generate a tree (parent-child) in json format from a map如何从地图生成 json 格式的树(父子)
【发布时间】:2021-07-15 12:59:27
【问题描述】:

我想要什么?

从地图中获取 JSON 格式的树。

要使用的数据:

一个映射(键值对),将键作为父项,将它们各自的值作为子项

代码: 以下代码使用示例数据,我以后想使用大数据意味着拥有更多的父母子女。如何从地图中构造父子关系?如果我需要任何其他信息来将地图数据解析为树结构,请告诉我?

type Nodes struct  {
      fn string
      children []*Nodes
}

func main() {
    var m map[string][]string
    m = make(map[string][]string)
    //map of parents(key) and child(values)
    m["root_node"] = []string{"1","2","3","4"}
    m["1"] = []string{"5","6"}
    m["2"] = []string{"7"}
    m["3"] = []string{"8", "9"}
    m["5"] = []string{"10"}
    m["7"] = []string{"11"}
    m["8"] = []string{"12","13"}

//json format: I don't know how to get root_node so expected result can be achieved
bytes, err := json.Marshal(root_node)
if err != nil {
    log.Fatal(err)
}
}

我的期望:

{
   "Funcname": "root_node",
   "Nodes": [
      {
         "Funcname": "1",
         "Nodes": [
            {
               "Funcname": "5",
               "Nodes": [
                  {
                     "Funcname": "10",
                     "Nodes": null
                  }
               ]
            },
            {
               "Funcname": "6",
               "Nodes": null
            }
         ]
      },
      {
         "Funcname": "2",
         "Nodes": [
            {
               "Funcname": "7",
               "Nodes": [
                  {
                     "Funcname": "11",
                     "Nodes": null
                  }
               ]
            }
         ]
      },
      {
         "Funcname": "3",
         "Nodes": [
            {
               "Funcname": "8",
               "Nodes": [
                  {
                     "Funcname": "12",
                     "Nodes": null
                  },
                  {
                     "Funcname": "13",
                     "Nodes": null
                  }
               ]
            },
            {
               "Funcname": "9",
               "Nodes": null
            }
         ]
      },
      {
         "Funcname": "4",
         "Nodes": null
      }
   ]
}

【问题讨论】:

    标签: go data-structures tree


    【解决方案1】:

    更简单的方法

    我们也可以说它是更简洁的方法,用构造函数语法构造节点。

    type Node struct {
        Name     string
        Children []*Node
    }
    
    func first_example() {
        root := Node{
            Name: "1",
            Children: []*Node{
                {
                    Name: "3",
                    Children: []*Node{
                        {
                            Name: "5",
                        },
                    },
                },
            },
        }
    
        bytes, err := json.Marshal(root)
        if err != nil {
            panic(err)
        }
    
        fmt.Println(string(bytes))
    }
    

    更难的方法

    输出是相同的,但它更加动态,并且允许您存储额外的值,另一方面,遍历树更烦人,因为您必须始终转换所有内容。

    func second_example() {
        root := map[string]interface{}{
            "Name": "1",
            "Children": []map[string]interface{}{
                {
                    "Name": "3",
                    "Children": []map[string]interface{}{
                        {
                            "Name": "5",
                        },
                    },
                },
            },
        }
    
        bytes, err := json.Marshal(root)
        if err != nil {
            panic(err)
        }
    
        fmt.Println(string(bytes))
    }
    

    输出

    {"Name":"1","Children":[{"Name":"3","Children":[{"Name":"5","Children":null}]}]} // #1
    {"Children":[{"Children":[{"Name":"5"}],"Name":"3"}],"Name":"1"} // #2
    

    编辑

    此外,这里还有向结构中插入节点的功能。如果操作失败,则返回 False。

    func (n *Node) InsertNode(path string, o *Node) bool {
        parts := strings.Split(path, " ")
        target := n
        for _, part := range parts {
            found := false
            for _, child := range target.Children {
                if child.Name == part {
                    target = child
                    found = true
                    break
                }
            }
            if !found {
                return false
            }
        }
    
        target.Children = append(target.Children, o)
        return true
    }
    
    func third_example() {
        root := &Node{Name: "1"}
        root.Children = append(root.Children, &Node{Name: "3"})
        root.InsertNode("3", &Node{Name: "5"})
    
        bytes, err := json.Marshal(root)
        if err != nil {
            panic(err)
        }
    
        fmt.Println(string(bytes))
    }
    

    【讨论】:

    • 感谢您的回答,但我想遍历地图然后创建树节点,而无需手动将每个值放入结构中。可能是通过使用我很困惑的范围或递归。
    • 那么你想要一个节点上的方法,不仅可以将新节点插入到顶层吗?
    • 是的,我想要一种方法,可以将数据从地图添加到节点,然后遍历这些节点以形成层次结构,然后最终将层次结构显示为 json。
    • @user248396 我添加了解决方案
    【解决方案2】:

    首先用AddChild()方法定义一个Node类型-

    type Node struct {
        Fn       string  `json:"Funcname"`
        Children []*Node `json:"Nodes"`
    }
    
    func (node *Node) AddChild(child *Node) {
        node.Children = append(node.Children, child)
    }
    

    为给定的fn构造一个新节点的构造函数-

    func CreateNewNode(fn string) *Node {
        newNode := new(Node)
        newNode.Fn = fn
        return newNode
    }
    

    要从地图生成树,请定义MakeTreeFromMap()function,如下所示 -

    // MakeTreeFromMap generates a tree from given map and returns pointer to root node of tree.
    func MakeTreeFromMap(treeMap map[string][]string, rootNodeFn string) *Node {
        cache := make(map[string]*Node)
        for fn, children := range treeMap {
            if _, nodeExists := cache[fn]; !nodeExists {
                node := CreateNewNode(fn)
                cache[fn] = node
            }
            for _, childFn := range children {
                if _, childExists := cache[childFn]; !childExists {
                    child := CreateNewNode(childFn)
                    cache[childFn] = child
                }
                cache[fn].AddChild(cache[childFn])
            }
        }
        return cache[rootNodeFn]
    }
    

    将树序列化为 JSON -

    root_node := MakeTreeFromMap(m, "root_node")
    bytes, err := json.Marshal(root_node)
    if err != nil {
        log.Fatal(err)
    }
    

    有关完整的工作示例,请参阅 Go Playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-15
      • 2018-05-23
      • 1970-01-01
      • 2021-01-17
      相关资源
      最近更新 更多