问题
I have a JSON tree structure with nodes that have children, and I would like to know how many nodes exist at a given level of the structure. I currently have this recursive structure:
var getNumNodesAtLevel = function (node, curr, desired) {
if (curr === (desired - 1)) {
return node.children.length;
} else {
var children = node.children;
children.forEach(function (child) {
return getNumNodesAtLevel(child, curr + 1, desired);
});
}
};
This doesn't work - any help would be appreciated!
回答1:
There are several flaws with the approach you show here.
Stopping the first time that a depth of the target depth is encountered will cause only the first set of children there to be counted, which is only going to be a subset.
Using an iteration function such as forEach will make calls in its iterations, but it will not return a value itself, and also the shown approach of using return inside of the callback has no effect.
forEach() executes the callback function once for each array element; unlike map() or reduce() it always returns the value undefined and is not chainable. The typical use case is to execute side effects at the end of a chain. -MDN: Array.prototype.forEach()
A better approach would be to analyze the entire tree structure for widths by depths, and once completed return the indexed value. It is possible to short circuit this by not recursing after the given depth, but I left in the full analysis in the object depths for a complete example.
As shown below, this uses an IIFE to recurse the tree, build an object whose key is the depth and whose value is the width, and then returns the associated width based on the input depth from the original function call.
var testObj = {
children : [
{ children : [ { children : [ ] } ] },
{ children : [ ] },
{ children : [ { children : [ ] } ] }
]
};
var getNumNodesAtLevel =
function (root, depth) {
var depths = {0:1};
(function recurTree(node,level){
level++;
if(depths[level] == void 0){
depths[level] = node.children.length;
}else{
depths[level] += node.children.length;
}
//optionally short circuit to avoid excessive recursion
//if(level+1 > depth) return;
for(var i = 0; i < node.children.length; i++){
recurTree(node.children[i],level);
}
})(root,0)
return depths[depth];
};
console.log(getNumNodesAtLevel(testObj,1));
console.log(getNumNodesAtLevel(testObj,2));
回答2:
You were close. You just had to store the children lengths somewhere.
Once one level fewer than the desired is reached, the function returns the length of children.
All the nodes higher in the tree will just add the values collected from children to zero and pass that back until root node is reached.
var getNumNodesAtLevel = function(node, curr, desired) {
if (curr === (desired - 1))
return node.children.length;
var count = 0;
node.children.forEach(function(child) {
count += getNumNodesAtLevel(child, curr + 1, desired);
});
return count;
};
The problem with this approach is that 0 will be returned when the desired level is larger than the depth of the tree or when it is zero (root level, should return 1).
To remedy that, you could make a closure and check for problematic values.
It is also not necessary to send the starting level manually each time.
var test = {
children : [
{ children : [ { children : [ ] } ] },
{ children : [ ] },
{ children : [ { children : [ ] } ] }
]
};
var getNumNodesAtLevel = (function() {
var getNumNodesAtLevel = function(node, curr, desired) {
if (curr === (desired - 1))
return node.children.length;
var count = 0;
node.children.forEach(function(child) {
count += getNumNodesAtLevel(child, curr + 1, desired);
});
return count;
};
return function(root, desired) {
if (desired === 0)
return 1;
var count = getNumNodesAtLevel(root, 0, desired);
if (count === 0)
return null; // you could throw an error here
return count;
};
}());
console.log(getNumNodesAtLevel(test, 0)); // 1
console.log(getNumNodesAtLevel(test, 1)); // 3
console.log(getNumNodesAtLevel(test, 2)); // 2
console.log(getNumNodesAtLevel(test, 3)); // null
console.log(getNumNodesAtLevel(test, 4)); // null
来源:https://stackoverflow.com/questions/38276188/get-number-of-nodes-at-given-level-of-json-tree