I have a hierarchy tree JSON with multiple level of nesting. When i am trying to loop through the JSON for displaying tree structure in UI. I am ending up with cyclic redundancy since parent ID is same at different level. I need to add unique identifiers for parentID and ID, so in recursive call it does not end up in infinite loop.
Sample JSON :
[
{
"id": "12",
"text": "Man"
},
{
"id": "6",
"parentId": "12",
"text": "Boy"
},
{
"id": "9",
"parentId": "6",
"text": "Boy-Boy"
},
{
"id": "13",
"parentId": "9",
"text": "Boy-Boy-Boy"
},
{
"id": "7",
"parentId": "12",
"text": "Other"
},
{
"id": "6",
"parentId": "7",
"text": "Boy"
},
{
"id": "9",
"parentId": "6",
"text": "Boy-Boy"
},
{
"id": "13",
"parentId": "9",
"text": "Boy-Boy-Boy"
}
I have tried by adding depth to each level but not able to maintain the ParentId and Id relationship.
var depthArray = []
function addDepth(arr, depth = 0) {
arr.forEach(obj => {
obj.id = obj.id + '-' + depth;
if(obj.children !== undefined) {
addDepth(obj.children, depth + 1)
}})
return arr;
}
[
{
"id": "12",
"text": "Man"
},
{
"id": "6",
"parentId": "12",
"text": "Boy"
},
{
"id": "9",
"parentId": "6",
"text": "Boy-Boy"
},
{
"id": "13",
"parentId": "9",
"text": "Boy-Boy-Boy"
},
{
"id": "7",
"parentId": "12",
"text": "Other"
},
{
"id": "6-1",
"parentId": "7",
"text": "Boy"
},
{
"id": "9-1",
"parentId": "6-1",
"text": "Boy-Boy"
},
{
"id": "13-1",
"parentId": "9-1",
"text": "Boy-Boy-Boy"
}
]
Your recursion does not work, what about this ?
But not sure how to rename IDs:
'use strict';
function addDepth(arr, id, depth) {
if(depth === undefined) depth = 0;
if(id !== undefined)
arr.forEach(obj => {
if(id == obj.parentId) {
if(depth) obj.parentId += '-' + depth;
addDepth(arr, obj.id, depth + 1)
}
})
else arr.forEach(obj => { addDepth(arr, obj.id, depth); });
return arr;
}
console.log(addDepth(
[
{
"id": "12",
"text": "Man"
},
{
"id": "6",
"parentId": "12",
"text": "Boy"
},
{
"id": "9",
"parentId": "6",
"text": "Boy-Boy"
},
{
"id": "13",
"parentId": "9",
"text": "Boy-Boy-Boy"
},
{
"id": "7",
"parentId": "12",
"text": "Other"
},
{
"id": "6",
"parentId": "7",
"text": "Boy"
},
{
"id": "9",
"parentId": "6",
"text": "Boy-Boy"
},
{
"id": "13",
"parentId": "9",
"text": "Boy-Boy-Boy"
}
]
));
Hard to guess how structure may look like, but made a supposed output by hand and then similar code - looking up only (not sure how to distinguish same records with parentId difference):
12 Man
12 6 Man Boy
12 6 9 Man Boy Boy-Boy
12 6 9 13 Man Boy Boy-Boy Boy-Boy-Boy
12 7 Man Other
12 7 Man Other Boy
12 7 6 9 Man Other Boy Boy-Boy
12 7 6 9 13 Man Other Boy Boy-Boy Boy-Boy-Boy
var data = GetData();
var arr = [data[0].text], parent;
for(var i=0;i<data.length;i++) {
if(parent = data[i].parentId) {
arr.push(data[i].text); // we have parentId, so iterate back
for(var j=i;j >= 0;j--) {
if(data[j].id == parent) {
arr.push(data[j].text); // & colect text properties
if(data[j].parentId) {
parent = data[j].parentId;
j = i;
}
}
}
}
console.log(arr.reverse().join(" -> "));
arr = [];
}
function GetData() { return [
{
"id": "12",
"text": "Man"
},
{
"id": "6",
"parentId": "12",
"text": "Boy"
},
{
"id": "9",
"parentId": "6",
"text": "Boy-Boy"
},
{
"id": "13",
"parentId": "9",
"text": "Boy-Boy-Boy"
},
{
"id": "7",
"parentId": "12",
"text": "Other"
},
{
"id": "6",
"parentId": "7",
"text": "Boy"
},
{
"id": "9",
"parentId": "6",
"text": "Boy-Boy"
},
{
"id": "13",
"parentId": "9",
"text": "Boy-Boy-Boy"
}
];
}
Related
The Overall Context is to find the leaf node of every parent(x) and children(x1) if there are more than 2 leaf nodes make them the child's as one under another
I Tried to use loadash in Nodejs but I was unable to get the expected result
I have a JSON Data
{
"Id": "1",
"name": "x",
"parent": "",
"children": [{
"Id": "2",
"name": "x1",
"parent": "1",
"children": [{
"Id": "3",
"name": "x2",
"parent": "2"
}, {
"Id": "4",
"name": "x3",
"parent": "2"
},
{
"Id": "5",
"name": "x4",
"parent": "2"
},
{
"Id": "6",
"name": "x5",
"parent": "2"
},
{
"Id": "7",
"name": "x6",
"parent": "2"
},
{
"Id": "8",
"name": "x7",
"parent": "2"
}
]
},
{
"Id": "9",
"name": "x8",
"parent": "1"
},
{
"Id": "10",
"name": "x10",
"parent": "1"
}, {
"Id": "11",
"name": "x9",
"parent": "1"
},
{
"Id": "12",
"name": "x11",
"parent": "1"
}
]
}
I would like to change into the below format
{
"Id": "1",
"name": "x",
"parent": "",
"children": [{
"Id": "2",
"name": "x1",
"parent": "1",
"children": [{
"Id": "3",
"name": "x2",
"IC": "Yes",
"parent": "2",
"children": [{
"Id": "5",
"name": "x4",
"IC": "Yes",
"parent": "2",
"children": [{
"Id": "7",
"parent": "2",
"name": "x6"
}]
}]
},
{
"Id": "4",
"name": "x3",
"IC": "Yes",
"parent": "2",
"children": [{
"Id": "5",
"name": "x5",
"IC": "Yes",
"parent": "2",
"children": [{
"Id": "7",
"name": "x7",
"IC": "Yes",
"parent": "2"
}]
}]
}
]
},
{
"Id": "9",
"name": "x8",
"parent": "1",
"children": [{
"Id": "10",
"name": "x10",
"IC": "Yes",
"parent": "1"
}]
},
{
"Id": "11",
"name": "x9",
"parent": "1",
"children": [{
"Id": "11",
"name": "x11",
"parent": "1",
"IC": "Yes"
}]
}
]
}
Note:
1. If there are 8 leaf nodes it should be split 4+4,
2. If there are 9 leaf nodes it should be split 5+4,
3. In the same way, If it has 13 it can be split into 7+6.
any help would be appreciated
thanks in advance
The following code will take all leaf nodes and create 2 even branches from them. The output is not identical to yours, but you mention in your comments that the branches can be built randomly from the leaf nodes, and this code respects that requirement.
const input = {
"name": "x",
"children": [
{
"name": "x1",
"children": [
{
"name": "x2"
},
{
"name": "x3"
},
{
"name": "x4"
},
{
"name": "x5"
},
{
"name": "x6"
},
{
"name": "x7"
}
]
},
{
"name": "x8"
},
{
"name": "x10"
},
{
"name": "x9"
},
{
"name": "x11"
}
]
};
function cutLeafNodes(node){
if(!node.children){
return;
}
const leaves = [];
const branches = [];
node.children.forEach(child => {
if(child.children){
branches.push(child);
} else {
leaves.push(child);
}
});
node.children = branches;
return leaves;
}
function reorderLeaves(nodes){
if(!nodes){
return;
}
const midpoint = nodes.length / 2;
const newChildren = [];
newChildren.push(createAncestry(nodes.splice(0, midpoint)));
newChildren.push(createAncestry(nodes));
return newChildren;
}
function createAncestry(nodes){
let currentChild = nodes[0];
const firstChild = currentChild;
for (let i = 1; i < nodes.length; i++) {
currentChild.children = [nodes[i]];
currentChild = currentChild.children[0];
}
return firstChild;
}
function reorganizeTree(node){
const leaves = cutLeafNodes(node);
if(node.children){
node.children.forEach(child => {
reorganizeTree(child);
});
}
if(leaves){
const newBranches = reorderLeaves(leaves);
newBranches.forEach(branch =>{
node.children.push(branch);
})
}
return node;
}
const output = reorganizeTree(input);
console.debug(output);
Below is the sample data(Hierarchical data) I want to only that array of object which has IsChecked = true and also all its children with condition isChecked =true.
$scope.treedData = [{
"id": "1",
"text": "Women",
"parentId": null,
"IsChecked": true,
"children": [{
"id": "4",
"text": "Jeans",
"parentId": "1",
"IsChecked": true,
"children": [
{ "id": "5", "text": "Jeans child", "parentId": "4", "IsChecked": true, "children": [] },
{ "id": "6", "text": "Jeans child child", "parentId": "4", "IsChecked": false, "children": [] }
]
}]
},
{
"id": "2",
"text": "Men",
"parentId": null,
"IsChecked": false,
"children": [{ "id": "10", "text": "Sweatshirts", "parentId": "2", "IsChecked": false, "children": [] }]
},
{
"id": "3",
"text": "Kids",
"parentId": null,
"IsChecked": true,
"children": [{ "id": "12", "text": "Toys", "parentId": "3", "IsChecked": false, "children": [] }]
}
];
You can use reduce for that, and use recursion to apply the filter to the children hierarchy as well:
var treeData = [
{ "id": "1", "text": "Women", "parentId": null, "IsChecked": true,
"children": [
{ "id": "4", "text": "Jeans", "parentId": "1", "IsChecked": false, "children":[
{ "id": "5", "text": "Jeans child", "parentId": "4", "IsChecked": true, "children":[] },
{ "id": "6", "text": "Jeans child child", "parentId": "4", "IsChecked": false, "children":[] }
] }]
},
{ "id": "2", "text": "Men", "parentId": null, "IsChecked": false,
"children": [{ "id": "10", "text": "Sweatshirts", "parentId": "2", "IsChecked": false, "children":[]}]
},
{"id": "3", "text": "Kids", "parentId": null, "IsChecked": true,
"children": [{ "id": "12", "text": "Toys", "parentId": "3", "IsChecked": false, "children":[] }]
}
];
checkedTreeData = treeData.reduce(function checkedOnly (acc, obj) {
return obj.IsChecked
? acc.concat(Object.assign({}, obj, { children: obj.children.reduce(checkedOnly, []) }))
: acc;
}, []);
console.log(checkedTreeData);
.as-console-wrapper { max-height: 100% !important; top: 0; }
NB: In JavaScript there is an unwritten rule to not use an initial capital letter for property names, so IsChecked would be with a lower case i: isChecked. Initial capital letters are commonly used for constructors (classes).
Alternative with .filter()
function filterChecked(treeData) {
return treeData.filter(obj => obj.IsChecked)
.map(obj => Object.assign({}, obj, obj.children ?
{ children: filterChecked(obj.children) } : {}))
}
var treeData = [
{ "id": "1", "text": "Women", "parentId": null, "IsChecked": true,
"children": [
{ "id": "4", "text": "Jeans", "parentId": "1", "IsChecked": false, "children":[
{ "id": "5", "text": "Jeans child", "parentId": "4", "IsChecked": true, "children":[] },
{ "id": "6", "text": "Jeans child child", "parentId": "4", "IsChecked": false, "children":[] }
] }]
},
{ "id": "2", "text": "Men", "parentId": null, "IsChecked": false,
"children": [{ "id": "10", "text": "Sweatshirts", "parentId": "2", "IsChecked": false, "children":[]}]
},
{"id": "3", "text": "Kids", "parentId": null, "IsChecked": true,
"children": [{ "id": "12", "text": "Toys", "parentId": "3", "IsChecked": false, "children":[] }]
}
];
console.log(filterChecked(treeData));
.as-console-wrapper { max-height: 100% !important; top: 0; }
use Lodash _.filter and _.every
_.filter(treedData, function(item) {
return _.every([
item.IsChecked,
_.every(item.children, 'IsChecked')
]);
});
if you also want to check condition of children of children you can do it recursively like
_.filter(treedData, function check(item) {
return _.every([
item.IsChecked,
_.size(item.children) === 0 || _.every(item.children, check)
]);
});
I am using angular JS and one of their examples:http://jsfiddle.net/furf/EJGHX/
I need to take the data when the update function occurs and add some values to it before I send to the server. (If doing this with angular instead of js would be better let me know)
I'm trying to get the 'parentid' and the 'index' and update the children.
Here is the data I'm looping through
{
"children": [{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": "1",
"children": [{
"id": "10",
"index": "0",
"text": "Grandstream GXP-21XX"
}, {
"id": "11",
"index": "1",
"text": "Polycom Soundstation/Soundpoint"
}, {
"id": "23",
"index": "2",
"text": "New Polycom"
}]
}, {
"id": "6",
"parentid": "0",
"text": "Pre-Sales Evaluation",
"index": "0",
"children": []
}, {
"id": "7",
"parentid": "0",
"text": "Router Setup Guides",
"index": "2",
"children": [{
"id": "9",
"index": "0",
"text": "Sonicwall"
}, {
"id": "12",
"index": "1",
"text": "Cisco"
}]
}, {
"id": "9",
"parentid": "7",
"text": "Sonicwall",
"index": "0",
"children": []
}, {
"id": "10",
"parentid": "5",
"text": "Grandstream GXP-21XX",
"index": "0",
"children": []
}, {
"id": "11",
"parentid": "5",
"text": "Polycom Soundstation/Soundpoint",
"index": "1",
"children": []
}, {
"id": "12",
"parentid": "7",
"text": "Cisco",
"index": "1",
"children": []
}, {
"id": "15",
"parentid": "0",
"text": "Post-Sales Implementation Check List",
"index": "7",
"children": [{
"id": "16",
"index": "0",
"text": "Porting and New Number Details"
}, {
"id": "18",
"index": "1",
"text": "Partner Setup"
}, {
"id": "19",
"index": "2",
"text": "test"
}, {
"id": "21",
"index": "3",
"text": "test"
}]
}, {
"id": "16",
"parentid": "15",
"text": "Porting and New Number Details",
"index": "0",
"children": []
}, {
"id": "18",
"parentid": "15",
"text": "Partner Setup",
"index": "1",
"children": []
}, {
"id": "19",
"parentid": "15",
"text": "test",
"index": "2",
"children": []
}, {
"id": "20",
"parentid": "0",
"text": "test",
"index": "11",
"children": []
}, {
"id": "21",
"parentid": "15",
"text": "test",
"index": "3",
"children": []
}, {
"id": "23",
"parentid": "5",
"text": "New Polycom",
"index": "2",
"children": []
}, {
"id": "24",
"parentid": "0",
"text": "Test Markup",
"index": "14",
"children": []
}, {
"id": "25",
"parentid": "0",
"text": "test",
"index": "15",
"children": []
}]
}
This is how I'm currently looping through it, but it only gets the first dimension
for (i = 0, l = data.length; i < l; i++) {
parentid = data[i].id == null ? '0' : data[i].id;
data[i].index = i;
if (data[i].children) {
if (data[i].children.length > 0) {
for (q = 0, r = data[i].children.length; q < r; q++) {
data[i].children[q].parentid = parentid;
data[i].children[q].index = q;
}
}
}
}
I found this one on another fiddle, but I don't know how I would grab the parentid or the index
$.each(target.children, function(key, val) { recursiveFunction(key, val) });
function recursiveFunction(key, val) {
actualFunction(key, val);
var value = val['children'];
if (value instanceof Object) {
$.each(value, function(key, val) {
recursiveFunction(key, val)
});
}
}
function actualFunction(key, val) {}
If I'm understanding you correctly, you want each 'child' to have a parentID (defined by its parent; 0 otherwise) and an index (based on its position within it sibling set).
function normalize(parent) {
if (parent && parent.children) {
for (var i = 0, l = parent.children.length; i < l; ++i) {
var child = parent.children[i];
child.index = i;
if (!child.parentId) child.parentId = parent.id || '0';
normalize(child);
}
}
}
normalize(data);
Recursion is calling function inside the same function. Your sample is not a recursion at all;
function runRecursive(input) {
for (var i = 0, l = input.length; i < l; i++) {
var current = input[i];
parentid = current.id == null ? '0' : current.id;
current.index = i;
if (current.children && current.children.length > 0) {
runRecursive(current.children);
};
};
};
runRecursive(data.children);
Also you should define i and l with var keyword, otherwise it will be located in window context and recursion logic will broken.
Though I don't get what is parentid variable for and why it defined outside visible code.
I grab a list of data from the server and I have to convert it.
Part of this is turning it into a 3 dimensional array. After the "myArr[i].children.push(temp);" it leaves copies of the objects that were pushed in the root of the array. Can I either push without copying or how would I delete these? (I have underscore js included, I know they have good array functions :))
for (var i = 0; i < myArr.length; i++) {
myArr[i].children = [];
for (var q = 0; q < myArr.length; q++) {
if (myArr[i].id == myArr[q].parentid) {
var temp = {
id: myArr[q].id,
index: myArr[q].index,
text: myArr[q].text
}
myArr[i].children.push(temp);
};
};
};
The Data
[{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": "0"
}, {
"id": "6",
"parentid": "0",
"text": "Pre-Sales Evaluation",
"index": "1"
}, {
"id": "7",
"parentid": "0",
"text": "Router Setup Guides",
"index": "2"
}, {
"id": "9",
"parentid": "7",
"text": "Sonicwall",
"index": "0"
}, {
"id": "10",
"parentid": "5",
"text": "Grandstream GXP-21XX",
"index": "1"
}, {
"id": "11",
"parentid": "5",
"text": "Polycom Soundstation\/Soundpoint",
"index": "2"
}, {
"id": "12",
"parentid": "7",
"text": "Cisco",
"index": "1"
}, {
"id": "15",
"parentid": "0",
"text": "Post-Sales Implementation Check List",
"index": "7"
}, {
"id": "16",
"parentid": "15",
"text": "Porting and New Number Details",
"index": "0"
}, {
"id": "18",
"parentid": "15",
"text": "Partner Setup",
"index": "1"
}, {
"id": "19",
"parentid": "15",
"text": "test",
"index": "2"
}, {
"id": "20",
"parentid": "0",
"text": "test",
"index": "11"
}, {
"id": "21",
"parentid": "15",
"text": "test",
"index": "3"
}, {
"id": "23",
"parentid": "5",
"text": "New Polycom",
"index": "0"
}, {
"id": "24",
"parentid": "0",
"text": "Test Markup",
"index": "14"
}, {
"id": "25",
"parentid": "0",
"text": "test",
"index": "15"
}]
After it is formated:
{
"children": [{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": "1",
"children": [{
"id": "10",
"index": "0",
"text": "Grandstream GXP-21XX"
}, {
"id": "11",
"index": "1",
"text": "Polycom Soundstation/Soundpoint"
}, {
"id": "23",
"index": "2",
"text": "New Polycom"
}]
}, {
"id": "6",
"parentid": "0",
"text": "Pre-Sales Evaluation",
"index": "0",
"children": []
}, {
"id": "7",
"parentid": "0",
"text": "Router Setup Guides",
"index": "2",
"children": [{
"id": "9",
"index": "0",
"text": "Sonicwall"
}, {
"id": "12",
"index": "1",
"text": "Cisco"
}]
}, {
"id": "9",
"parentid": "7",
"text": "Sonicwall",
"index": "0",
"children": []
}, {
"id": "10",
"parentid": "5",
"text": "Grandstream GXP-21XX",
"index": "0",
"children": []
}, {
"id": "11",
"parentid": "5",
"text": "Polycom Soundstation/Soundpoint",
"index": "1",
"children": []
}, {
"id": "12",
"parentid": "7",
"text": "Cisco",
"index": "1",
"children": []
}, {
"id": "15",
"parentid": "0",
"text": "Post-Sales Implementation Check List",
"index": "7",
"children": [{
"id": "16",
"index": "0",
"text": "Porting and New Number Details"
}, {
"id": "18",
"index": "1",
"text": "Partner Setup"
}, {
"id": "19",
"index": "2",
"text": "test"
}, {
"id": "21",
"index": "3",
"text": "test"
}]
}, {
"id": "16",
"parentid": "15",
"text": "Porting and New Number Details",
"index": "0",
"children": []
}, {
"id": "18",
"parentid": "15",
"text": "Partner Setup",
"index": "1",
"children": []
}, {
"id": "19",
"parentid": "15",
"text": "test",
"index": "2",
"children": []
}, {
"id": "20",
"parentid": "0",
"text": "test",
"index": "11",
"children": []
}, {
"id": "21",
"parentid": "15",
"text": "test",
"index": "3",
"children": []
}, {
"id": "23",
"parentid": "5",
"text": "New Polycom",
"index": "2",
"children": []
}, {
"id": "24",
"parentid": "0",
"text": "Test Markup",
"index": "14",
"children": []
}, {
"id": "25",
"parentid": "0",
"text": "test",
"index": "15",
"children": []
}]
}
Here you go
tree = {0: {children: []}}
data.forEach(function(x) {
x.children = tree[x.id] ? tree[x.id].children : [];
tree[x.id] = x;
if(!tree[x.parentid])
tree[x.parentid] = {children: []}
tree[x.parentid].children.push(x)
})
result = tree[0].children
This solution is linear (iterates over the array just once) and doesn't require any pre-sorting.
http://jsfiddle.net/U47WY/
and here's how to convert the tree back to the linear array:
function flatten(source) {
return source.reduce(function(a, x) {
var children = x.children;
delete x.children;
return a.concat([x], flatten(x.children))
}, []);
}
Following on from a friendly discussion in the comments :
var zeroObj = {"children":[]};
for (var i = 0; i < myArr.length; i++) {
if(myArr[i].parentid === 0) {
zeroObj.children.push(myArr[i]);
} else {
for (var q = 0; q < myArr.length; q++) {
if (myArr[i].parentid == myArr[q].id) {
myArr[q].children = myArr[q].children || [];
myArr[q].children.push(myArr[i]);
};
};
}
};
I have to convert JSON to the format below, I'm having a problem converting it back.
Here is the current format
[{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": 0,
"children": [{
"id": "10",
"text": "Grandstream GXP-21XX",
"index": 0
}, {
"id": "11",
"text": "Polycom Soundstation/Soundpoint",
"index": 1
}, {
"id": "23",
"text": "New Polycom",
"index": 2
}]
}, {
"id": "6",
"parentid": "0",
"text": "Pre-Sales Evaluation",
"index": 1,
"children": []
}, {
"id": "7",
"parentid": "0",
"text": "Router Setup Guides",
"index": 2,
"children": [{
"id": "9",
"text": "Sonicwall",
"index": 0
}, {
"id": "12",
"text": "Cisco",
"index": 1
}]
}, {
"id": "9",
"parentid": "7",
"text": "Sonicwall",
"index": 3,
"children": []
}, {
"id": "10",
"parentid": "5",
"text": "Grandstream GXP-21XX",
"index": 4,
"children": []
}, {
"id": "11",
"parentid": "5",
"text": "Polycom Soundstation/Soundpoint",
"index": 5,
"children": []
}, {
"id": "12",
"parentid": "7",
"text": "Cisco",
"index": 6,
"children": []
}]
Here is the format I need it in:
[{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": "0"
}, {
"id": "6",
"parentid": "0",
"text": "Pre-Sales Evaluation",
"index": "0"
}, {
"id": "7",
"parentid": "0",
"text": "Router Setup Guides",
"index": "0"
}, {
"id": "9",
"parentid": "7",
"text": "Sonicwall",
"index": "0"
}, {
"id": "10",
"parentid": "5",
"text": "Grandstream GXP-21XX",
"index": "0"
}, {
"id": "11",
"parentid": "5",
"text": "Polycom Soundstation\/Soundpoint",
"index": "0"
}, {
"id": "12",
"parentid": "7",
"text": "Cisco",
"index": "0"
}]
Basically, I have to nest it for the script I'm using but the server is expecting to see it flattened, in the current format the 3rd object dimension starts with "children". I need to unnest children and keep the objects going like the format I need it in.
A first solution, granted you don't want the resulting array to be sorted based on the id:
function visitor(graph) {
var i, l,
nodes=[],
visited=[];
function clone(n) {
// improve the function yourself I'm lazy
var i,l,
props=["id","parentid","index","text"],
result={};
for (i = 0, l = props.length; i < l; i++) {
if (n[props[i]]) {
result[props[i]]= n[props[i]];
}
}
return result;
}
function helper (node) {
var i, limit;
if (visited.indexOf(node.id) == -1) {
visited.push(node.id);
nodes.push(clone(node));
if( node.children) {
for (i = 0, limit = node.children.length; i < limit; i++) {
helper(node.children[i]);
}
}
}
}
for (i = 0, l = graph.length; i < l; i++) {
helper(graph[i]);
}
return nodes;
}
var graph = [{
"id": "5",
"parentid": "0",
"text": "Device Guides",
"index": 0,
"children": [{
"id": "10",
"text": "Grandstream GXP-21XX",
"index": 0
}, {
"id": "11",
"text": "Polycom Soundstation/Soundpoint",
"index": 1
}, {
"id": "23",
"text": "New Polycom",
"index": 2
}]
}, {
"id": "6",
"parentid": "0",
"text": "Pre-Sales Evaluation",
"index": 1,
"children": []
}, {
"id": "7",
"parentid": "0",
"text": "Router Setup Guides",
"index": 2,
"children": [{
"id": "9",
"text": "Sonicwall",
"index": 0
}, {
"id": "12",
"text": "Cisco",
"index": 1
}]
}, {
"id": "9",
"parentid": "7",
"text": "Sonicwall",
"index": 3,
"children": []
}, {
"id": "10",
"parentid": "5",
"text": "Grandstream GXP-21XX",
"index": 4,
"children": []
}, {
"id": "11",
"parentid": "5",
"text": "Polycom Soundstation/Soundpoint",
"index": 5,
"children": []
}, {
"id": "12",
"parentid": "7",
"text": "Cisco",
"index": 6,
"children": []
}];
nodes = visitor(graph);
And yes, I know, the helper function relay on side effects but I've scoped them into the visitor function to reduce harm and there is room for improvements (at least sorting the resulting array based on the id) but I will leave them to you