Reputation: 171341
I have multiple trees, for example:
a h
| \ |
b c i
/ | \ / \
d e f j k
| / | \
g l m n
which represented in a single JavaScript object like this:
{ 'a': ['b', 'c'],
'b': null,
'c': ['d', 'e', 'f'],
'd': null,
'e': ['g'],
'f': null,
'g': null,
'h': ['i'],
'i': ['j', 'k'],
'j': ['l', 'm', 'n'],
'k': null,
'l': null,
'm': null,
'n': null }
i.e. all the nodes appears as keys, and the value of a particular key/node is an array of all its children (or null
if it doesn't have children).
I would like to construct two things:
An array of all roots. In this example: ['a', 'h']
For every root, an array of all its descendants, including the root. In this example:
['a', 'b', 'c', 'd', 'e', 'f', 'g']
['h', 'i', 'j', 'k', 'l', 'm', 'n']
The order of the elements in the resulting arrays doesn't matter.
Could you suggest an elegant method to implement this in JavaScript (jQuery allowed).
Upvotes: 1
Views: 730
Reputation: 664513
var tree = {...};
var roots = [], rootdescendants = {};
tl: for (var p in tree) { // tree-loop
for (var r in rootdescendants)
// check if p is already in one of the result arrays
if (rootdescendants[r].lastIndexOf(p)>-1)
continue tl;
var d = rootdescendants[p] = [p]; // create new descendants array
for (var i=0; i<d.length; i++) {
var c = d[i];
if (i>0 && c in rootdescendants) { // there is already an array for c
i += rootdescendants[c].unshift(i, 1) - 3;
Array.prototype.splice.apply(d, rootdescendants[c]); // insert into d
delete rootdescendants[c];
} else {
if (tree[c]) // not null
Array.prototype.push.apply(d, tree[c]);
}
}
}
roots = Object.keys(rootdescendants);
Upvotes: 0
Reputation: 8230
var src = { 'a': ['b', 'c'],
'b': null,
'c': ['d', 'e', 'f'],
'd': null,
'e': ['g'],
'f': null,
'g': null,
'h': ['i'],
'i': ['j', 'k'],
'j': ['l', 'm', 'n'],
'k': null,
'l': null,
'm': null,
'n': null };
/* ******************************************************************* */
var roots={},p1,p2,isRoot,i=-1;
for(p1 in src){
isRoot=true;
for(p2 in src)if(src[p2]&&src[p2].indexOf(p1)>-1){isRoot=false;break;}
if(isRoot)roots[p1]=[p1];
}
for(p1 in roots){
i=-1;
while(++i<roots[p1].length)
if(src[roots[p1][i]]&&src[roots[p1][i]].length)
Array.prototype.push.apply(roots[p1],src[roots[p1][i]]);
}
As a result roots
variable contains next value for your second task:
roots: {
"a": ["a", "b", "c", "d", "e", "f", "g"],
"h": ["h", "i", "j", "k", "l", "m", "n"]
}
And for your first task Object.keys(roots)
returns needed array.
Upvotes: 1