My data has these properties:
- Each entry has a unique id (Id)
- Each has a Parent field, which points to the Id of the parent.
- A node can have multiple children, but only one parent.
My first attempt to build a tree is below. It is buggy as the recursion causes an infinite loop. Even if I solve it, I am not sure if there is a better approach to do this. Currently, I am doing it in 2 passes.
I would like it to be as efficient as possible as I have a decent amount of data. It also needs to rebuild the tree dynamically (the root can be any node)
There is sample data in the program below:
arry = [{Id:1, Name:abc, Parent:}, {Id:2, Name:abc, Parent:1},
{Id:3, Name:abc, Parent:2},{Id:4, Name:abc, Parent:2}]//for testing
I was hoping the output to be (it might be wrong nested structure, as I manually wrote it. but, what I am hoping is a valid JSON structure with node as a field 'value' and children as an array.)
{
value: {Id:1, Name:abc, Parent:},
children: [
{
value: {Id:2, Name:abc, Parent:1},
children: [
{
value: {Id:3, Name:abc, Parent:2},
children: []
},
{
value: {Id:4, Name:abc, Parent:2},
children: []
}
]
..
}
Sample program:
function convertToHierarchy(arry, root)
{
//root can be treated a special case, as the id is known
arry = [{Id:1, Name:abc, Parent:}, {Id:2, Name:abc, Parent:1},
{Id:3, Name:abc, Parent:2},{Id:4, Name:abc, Parent:2}]//for testing
var mapping = {}; // parent : [children]
for (var i = 0; i < array.length; i++)
{
var node = arry[i];
if (!mapping[node.Id]) {
mapping[node.Id] = {value: node, children:[] } ;
}else{
mapping[node.Id] = {value: node} //children is already set
}
if (!mapping[node.Parent]) { //TODO what if parent doesn't exist.
mapping[node.Parent] = {value: undefined, children:[ {value: node,children:[]} ]};
}else {//parent is already in the list
mapping[node.Parent].children.push({value: node,children:[]} )
}
}
//by now we will have an index with all nodes and their children.
//Now, recursively add children for root element.
var root = mapping[1] //hardcoded for testing, but a function argument
recurse(root, root, mapping)
console.log(root)
//json dump
}
function recurse(root, node, mapping)
{
var nodeChildren = mapping[node.value.Id].children;
root.children.push({value:node.value, children:nodeChildren})
for (var i = 0; i < nodeChildren.length; i++) {
recurse(root, nodeChildren[i], mapping);
}
return root;
}
I have 3 good solutions so far, and hope the upvotes suggest more idiomatic, efficient implementation. I am not sure, utilizing the property of my data that, there will be only one root element in the set of input array, and also the root is always given, any of these implementation could be better. I should also be learning how to benchmark, as my requirement is how efficiently (fast/without much memory) the tree can be rebuild. For example, the input is already cached (array) and rebuild the tree like
convertToHierarchy(parentid)
....
convertToHierarchy(parentid2)
...