How to break out of loops in recursive functions?

I work with an array of category objects that can have an array of child categories. The tricky part is that the depth of this nested data is unknown (and may change). (See the sample below.) What I am trying to do is return the “trace” to the category object, but I have all kinds of difficulties.

Ideally, something like findCategory('b4') will return: ['c1', 'd2', 'd3', 'b4'] (see example).

I think that my problem is that I am having problems with correctly exiting nested loops caused by my recursion. Sometimes I get additional categories in my trail, or when I think I break out, some deeper nested category gets on the trail.

One result may look like this. Obviously, this does not kill the cycle on b4, and I'm not sure why the result is found twice.

 b4 FOUND ["c1", "d2", "d3", "b4"] e2 FOUND ["c1", "d2", "d3", "b4", "e2"] 

Bonus if you can also show me the version of underscore.js.

JSFiddle link here ...

 // Start function function findCategory(categoryName) { var trail = []; var found = false; function recurse(categoryAry) { for (var i=0; i < categoryAry.length; i++) { console.log(categoryAry[i].category); trail.push(categoryAry[i].category); // Found the category! if ((categoryAry[i].category === categoryName) || found) { console.log('FOUND'); found = true; console.log(trail); break; // Did not match... } else { // Are there children / sub-categories? YES if (categoryAry[i].children.length > 0) { console.log('recurse'); recurse(categoryAry[i].children); // NO } else { trail.pop(); if (i === categoryAry.length - 1) { trail.pop(); } } } } } return recurse(catalog); } console.clear(); console.log(findCategory('b4')); 

eg. Array category objects with an embedded array of category objects. Assume that the nesting depth is unknown.

 var catalog = [ { category:"a1", children:[ { category:"a2", children:[] }, { category:"b2", children:[ { category:"a3", children:[] }, { category:"b3", children:[] } ] }, { category:"c2", children:[] } ] }, { category:"b1", children:[] }, { category:"c1", children:[ { category:"d2", children:[ { category:"c3", children:[] }, { category:"d3", children:[ { category:"a4", children:[] }, { category:"b4", children:[] }, { category:"c4", children:[] }, { category:"d4", children:[] } ] } ] }, { category:"e2", children:[ { category:"e3", children:[] } ] } ] } ]; 
+4
source share
2 answers

Try

 function findCategory(categoryName) { var trail = []; var found = false; function recurse(categoryAry) { for (var i = 0; i < categoryAry.length; i++) { trail.push(categoryAry[i].category); // Found the category! if ((categoryAry[i].category === categoryName)) { found = true; break; // Did not match... } else { // Are there children / sub-categories? YES if (categoryAry[i].children.length > 0) { recurse(categoryAry[i].children); if(found){ break; } } } trail.pop(); } } recurse(catalog); return trail } 

Demo: Fiddle

+16
source

return stmt really works, but remember that it will be called every time the loop is turned off, and that’s not what you are looking at. Example

 // global scope String matchingVariable; int getMatch(index count, String input, String[] inputs){ if(isValid(input) || count < inputs.length){ // your condition is met and break // assign your value to global scope variable matchingVariable = input; }else if(matchingVariable ==null){ ++count if(count < inputs.length){ getMatch(count, input+inputs[count], inputs) } // NOTE RETURN - I WOULDN'T DO THIS return input; // doesn't work instead assign the input to global scope variable when a match is found. } } 
0
source

All Articles