如何从一个映射生成以 JSON 格式表示的树(父子关系)?

huangapple go评论73阅读模式
英文:

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

问题

我明白了,你想要将一个Map转换为JSON格式的树结构。以下是你提供的代码的翻译结果:

type Nodes struct {
    Funcname string
    Nodes    []*Nodes
}

func main() {
    var m map[string][]string
    m = make(map[string][]string)
    // 父节点(key)和子节点(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格式
    root_node := &Nodes{
        Funcname: "root_node",
        Nodes:    buildTree("root_node", m),
    }

    // 将树结构转换为JSON格式
    bytes, err := json.Marshal(root_node)
    if err != nil {
        log.Fatal(err)
    }
}

// 递归构建树结构
func buildTree(node string, m map[string][]string) []*Nodes {
    children, ok := m[node]
    if !ok {
        return nil
    }

    nodes := make([]*Nodes, len(children))
    for i, child := range children {
        nodes[i] = &Nodes{
            Funcname: child,
            Nodes:    buildTree(child, m),
        }
    }

    return nodes
}

期望的JSON格式如下所示:

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

希望能对你有所帮助!如果你需要进一步的解释或有其他问题,请随时提问。

英文:

What do I want?

To get a tree in JSON format from a Map.

Data to be used:

A map (key-value pairs), having keys as parents and their respective values as children

Code:
The following code uses sample data, I want to use big data later on means having more parents-children. How can I structure parent-child from a Map? Please let me know if I need any other information to parse Map data into a tree structure?

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

My expectation:

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

答案1

得分: 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))
}
英文:

easier approach

We can also say that it is cleaner approach, to construct nodes with constructor syntax.

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

harder approach

The output is the same but its lot more dynamic and allows you to store additional values, On the other hand traversing the tree is lot more annoying as you have to always cast everything.

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

output

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

edit

In addition here is the function to insert a node to the structure. False is returned if operation fails.

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

答案2

得分: 0

首先定义一个具有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从给定的映射生成树,并返回指向树根节点的指针。
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

英文:

First define a Node type with AddChild() method -

type Node struct {
	Fn       string  `json:"Funcname"`
	Children []*Node `json:"Nodes"`
}

func (node *Node) AddChild(child *Node) {
	node.Children = append(node.Children, child)
}

A constructor function to construct a new node for given fn -

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

To generate a tree from map define MakeTreeFromMap()function as follows -

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

Serialize tree into JSON -

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

See Go Playground for full working example.

huangapple
  • 本文由 发表于 2021年7月14日 19:15:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/68377034.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定