使用Golang如何从表格创建一棵树?

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

make a tree from a table using golang?

问题

我想从一个表格中创建一棵树。表格如下所示:

OrgID   OrgName        parentID
A001    Dept           0 -----顶级
A002    subDept1        A001
A003    sub_subDept    A002
A006    gran_subDept   A003
A004    subDept2        A001 

我希望结果如下所示,使用Go语言如何实现:

<pre>
Dept

--subDept1

----sub_subDept

------gran_subDept

--subDept2
</pre>

英文:

I want to make a tree from a table.
the table is as following:

OrgID   OrgName        parentID
A001    Dept           0 -----th top
A002    subDept1        A001
A003    sub_subDept    A002
A006    gran_subDept   A003
A004    subDept2        A001 

and i want the result is as following,how to do it using go:
<pre>
Dept

--subDept1

----sub_subDept

------gran_subDept

--subDept2
</pre>

答案1

得分: 10

如果你想将这些行解析为树结构,可以按照以下方式进行:

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

type Node struct {
	name     string
	children []*Node
}

var (
	nodeTable = map[string]*Node{}
	root      *Node
)

func add(id, name, parentId string) {
	fmt.Printf("add: id=%v name=%v parentId=%v\n", id, name, parentId)

	node := &Node{name: name, children: []*Node{}}

	if parentId == "0" {
		root = node
	} else {

		parent, ok := nodeTable[parentId]
		if !ok {
			fmt.Printf("add: parentId=%v: not found\n", parentId)
			return
		}

		parent.children = append(parent.children, node)
	}

	nodeTable[id] = node
}

func scan() {
	input := os.Stdin
	reader := bufio.NewReader(input)
	lineCount := 0
	for {
		lineCount++
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		}
		if err != nil {
			fmt.Printf("error reading lines: %v\n", err)
			return
		}
		tokens := strings.Fields(line)
		if t := len(tokens); t != 3 {
			fmt.Printf("bad input line %v: tokens=%d [%v]\n", lineCount, t, line)
			continue
		}
		add(tokens[0], tokens[1], tokens[2])
	}
}

func showNode(node *Node, prefix string) {
	if prefix == "" {
		fmt.Printf("%v\n\n", node.name)
	} else {
		fmt.Printf("%v %v\n\n", prefix, node.name)
	}
	for _, n := range node.children {
		showNode(n, prefix+"--")
	}
}

func show() {
	if root == nil {
		fmt.Printf("show: root node not found\n")
		return
	}
	fmt.Printf("RESULT:\n")
	showNode(root, "")
}

func main() {
	fmt.Printf("main: reading input from stdin\n")
	scan()
	fmt.Printf("main: reading input from stdin -- done\n")
	show()
	fmt.Printf("main: end\n")
}
英文:

If you want to parse the lines into a tree structure, this is a way to do it:

package main
import (
&quot;bufio&quot;
&quot;fmt&quot;
&quot;io&quot;
&quot;os&quot;
&quot;strings&quot;
)
type Node struct {
name     string
children []*Node
}
var (
nodeTable = map[string]*Node{}
root      *Node
)
func add(id, name, parentId string) {
fmt.Printf(&quot;add: id=%v name=%v parentId=%v\n&quot;, id, name, parentId)
node := &amp;Node{name: name, children: []*Node{}}
if parentId == &quot;0&quot; {
root = node
} else {
parent, ok := nodeTable[parentId]
if !ok {
fmt.Printf(&quot;add: parentId=%v: not found\n&quot;, parentId)
return
}
parent.children = append(parent.children, node)
}
nodeTable[id] = node
}
func scan() {
input := os.Stdin
reader := bufio.NewReader(input)
lineCount := 0
for {
lineCount++
line, err := reader.ReadString(&#39;\n&#39;)
if err == io.EOF {
break
}
if err != nil {
fmt.Printf(&quot;error reading lines: %v\n&quot;, err)
return
}
tokens := strings.Fields(line)
if t := len(tokens); t != 3 {
fmt.Printf(&quot;bad input line %v: tokens=%d [%v]\n&quot;, lineCount, t, line)
continue
}
add(tokens[0], tokens[1], tokens[2])
}
}
func showNode(node *Node, prefix string) {
if prefix == &quot;&quot; {
fmt.Printf(&quot;%v\n\n&quot;, node.name)
} else {
fmt.Printf(&quot;%v %v\n\n&quot;, prefix, node.name)
}
for _, n := range node.children {
showNode(n, prefix+&quot;--&quot;)
}
}
func show() {
if root == nil {
fmt.Printf(&quot;show: root node not found\n&quot;)
return
}
fmt.Printf(&quot;RESULT:\n&quot;)
showNode(root, &quot;&quot;)
}
func main() {
fmt.Printf(&quot;main: reading input from stdin\n&quot;)
scan()
fmt.Printf(&quot;main: reading input from stdin -- done\n&quot;)
show()
fmt.Printf(&quot;main: end\n&quot;)
}

答案2

得分: 5

根据你的问题和评论提供的信息,可以解决你的问题的是一个普通的递归循环。

package main

import "fmt"

type Org struct {
	OrgID    string
	OrgName  string
	parentID string
}

func printTree(tbl []Org, parent string, depth int) {
	for _, r := range tbl {
		if r.parentID == parent {
			for i := 0; i < depth; i++ {
				fmt.Print("--")
			}
			fmt.Print(r.OrgName, "\n\n")
			printTree(tbl, r.OrgID, depth+1)
		}
	}
}

func main() {
	data := []Org{
		{"A001", "Dept", "0 -----th top"},
		{"A002", "subDept1", "A001"},
		{"A003", "sub_subDept", "A002"},
		{"A006", "gran_subDept", "A003"},
		{"A004", "subDept2", "A001"},
	}

	printTree(data, "0 -----th top", 0)
}

结果:

Dept
--subDept1
----sub_subDept
------gran_subDept
--subDept2

Playground: http://play.golang.org/p/27CQAhI8gf

请注意,如果父级是其自己子级的后代,这个递归函数可能会陷入循环中。

英文:

With the information provided in your question and comment, what could solve your problem is an ordinary recursive loop.

package main
import &quot;fmt&quot;
type Org struct {
OrgID    string
OrgName  string
parentID string
}
func printTree(tbl []Org, parent string, depth int) {
for _, r := range tbl {
if r.parentID == parent {
for i := 0; i &lt; depth; i++ {
fmt.Print(&quot;--&quot;)
}
fmt.Print(r.OrgName, &quot;\n\n&quot;)
printTree(tbl, r.OrgID, depth+1)
}
}
}
func main() {
data := []Org{
{&quot;A001&quot;, &quot;Dept&quot;, &quot;0 -----th top&quot;},
{&quot;A002&quot;, &quot;subDept1&quot;, &quot;A001&quot;},
{&quot;A003&quot;, &quot;sub_subDept&quot;, &quot;A002&quot;},
{&quot;A006&quot;, &quot;gran_subDept&quot;, &quot;A003&quot;},
{&quot;A004&quot;, &quot;subDept2&quot;, &quot;A001&quot;},
}
printTree(data, &quot;0 -----th top&quot;, 0)
}

Result:

Dept
--subDept1
----sub_subDept
------gran_subDept
--subDept2

Playground: http://play.golang.org/p/27CQAhI8gf

Be aware that this recursive function might get stuck in an loop incase there if a parent is the descendant of its own child.

huangapple
  • 本文由 发表于 2014年4月9日 17:02:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/22957638.html
匿名

发表评论

匿名网友

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

确定