Wind Up Toy Wind Up Toy - 1 year ago 44
Javascript Question

Recursively creating a JSON tree, adding only at the deepest level

I want to create a JSON hierarchy structure of unknown objects, so it must be handled recursively.

Here's my function, where

angular.element.isEmptyObject()
is inherited from jQuery, and
angular.copy()
is a function that creates a deep copy of the object (I'm using AngularJS).

function recurseTree(tree, newKey, newId) {
if(angular.element.isEmptyObject(tree)) {
tree[newKey] = {_id: newId};
} else {
for(var key in tree) {
if(typeof tree[key] == 'object') recurseTree(tree[key], newKey, newId);
else tree[newKey] = {_id: newId};
}
}
return angular.copy(tree);
}


Now run this:

var testT = {};
console.log(recurseTree(testT, 'a', '1'));
console.log(recurseTree(testT, 'b', '2'));
console.log(recurseTree(testT, 'c', '3'));
console.log(recurseTree(testT, 'd', '4'));
console.log(recurseTree(testT, 'e', '5'));


You'll notice that the first and second ones return as expected:

{
a: {
_id: '1',
b: {
_id: '2'
}
}
}


but the third one is where I run into trouble.

{
a: {
_id: '1',
b: {
_id: '2',
c: {
_id: '3'
}
},
c: {
_id: '3'
}
}
}


What do I need to fix to get the
c
object appended ONLY as a child of
b
, rather than also as a child of
a
? I'm stumped.

Here's a JSFiddle of it in action, check your console for the results. http://jsfiddle.net/winduptoy/Mjq5D/2/

Answer Source

Try this:

function recurseTree(tree, newKey, newId) {
    if(angular.element.isEmptyObject(tree)) {
        tree[newKey] = {_id: newId};
        return;
    } 

    var child = null; // find current tree's child
    for(var key in tree) {
        if (key != '_id') {
            child = tree[key]; // found a child
            break;
        }
    }
    if (child) { // recursively process on child
        recurseTree(child, newKey, newId);
    } else { // no child, so just fill the tree
        tree[newKey] = {_id: newId};
    }
}

Test:

var testT = {};
recurseTree(testT, 'a', '1');
console.log(testT);  
recurseTree(testT, 'b', '1');
console.log(testT); 
recurseTree(testT, 'c', '1');
console.log(testT); 
recurseTree(testT, 'd', '1');
console.log(testT); 
recurseTree(testT, 'e', '1');
console.log(testT);

Please be noted that I have not used angular.copy(tree) for the performance's sake. If you don't want to change the tree, copy it before passing it to the function recurseTree. Please try it on jsFiddle.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download