如何从地图生成 json 格式的树(父子)

How to generate a tree (parent-child) in json format from a map

我想要什么?

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

要使用的数据:

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

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

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
      }
   ]
}

更简单的方法

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

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))
}

先用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()函数如下 -

// 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