Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get a tree like structure out of path string

Tags:

recursion

tree

go

I am stuck since 2 days, as I am not to firm with pointers and recursion. I have an array of path like structures, lets say:

s:=[]string {
  "a/b/c",
  "a/b/g",
  "a/d",
}

With a data structure like this:

 type Node struct {
   Name     string `json:"name"`
   Children []Node `json:"children"`
}

I would like to end up with something like this:

{
 "name": "a",
 "children": [
     {
      "name": "b",
      "children": [
        {
         "name": "c",
         "children": []
        },
        {
         "name": "g",
         "children": []
        }
      ]
    },
    {
     "name": "d",
     "children": []
    }
  ]
}

I tried to build it with a recursion, which works kind of fine, but only for one string (e.g. "a/b/c"), as soon as I try to implement something which should add missing nodes ("g" in "a/b/g") to a tree I am stuck.

I had something like:

func appendChild(root Node, children []string) Node {
   if len(children) == 1 {
      return Node{children[0], nil}
   } else {
      t := root
      t.Name=children[0]
      t.Children = append(t.Children, appendChild(root, children[1:]))
      return t
   }
}

Could someone point me to an efficient solution?

like image 357
hanneslehmann Avatar asked May 05 '17 13:05

hanneslehmann


1 Answers

https://play.golang.org/p/9pER5cwChF

func AddToTree(root []Node, names []string) []Node {
    if len(names) > 0 {
        var i int
        for i = 0; i < len(root); i++ {
            if root[i].Name == names[0] { //already in tree
                break
            }
        }
        if i == len(root) {
            root = append(root, Node{Name: names[0]})
        }
        root[i].Children = AddToTree(root[i].Children, names[1:])
    }
    return root
}

Example output (note that I used omitempty on the children field, because I don't like null entries in my JSONs):

[{
    "name": "a",
    "children": [{
        "name": "b",
        "children": [{
            "name": "c"
        }, {
            "name": "g"
        }]
    }, {
        "name": "d"
    }]
}]

Notable difference from your version:

  • It operates on a list of nodes instead of the children of a single node. This is important, as your version assumes that all of the trees have the same single root node (a), when this might not be the case. The only way to handle that in your version is to have a "fake" node at the root.
  • It does NOT reuse the input node. This is one of the primary problems with your code. If len(children) > 1, you update the input node's name, append to it's children, then recurse. This means that every prior level of the slice becomes part of the children. You need to create a new node instead.
  • It actually searches the tree. You're not searching the tree to see if the item being inserted already exists, so you duplicate nodes (specifically, node b)
like image 168
Kaedys Avatar answered Sep 29 '22 11:09

Kaedys