I'm trying to get a result looking something like this: Miniors | Boys | 54kg - 62kg
where every value delimited by a pipe | comes from an array containing a certain "type of restriction". For example: ageGroups, genders, weightClasses
(as seen above).
The way I'm able to get this result right now is if I hard code the nested forEach-loops (using underscorejs), but this means I have to now how many arrays I have to loop over to get wanted result. This works "fine":
var categories = [];
_.each(ageGroups, function(ageGroup) {
_.each(gender, function(gender) {
_.each(weightClasses, function(weightClass) {
categories.push(ageGroup.name + ' | ' + gender.name + ' | ' + weightClass.name);
});
});
});
The output is an array (categories) with all the possible combinations of the restriction arrays.
Now, my problem is that I need a way to do the same with an unknown number of restriction arrays. My guess for a proper solution is recursion, BUT I haven't been able to produce anything that actually works since I'm not able to wrap my head around recursion just yet :)
A fiddle prepared with some test data can be found here: jsFiddle. The fiddle uses angular for some simple databinding and debugging the result output and underscorejs for handling the arrays.
To implement a dynamic nested loop we need to increment the inner most loop variable until we run out values. Only then do we need to look at changing the upper level loop variables.
Recursion can be seen as "just" another way of doing loops. The main advantage is code readability, as you can see in this Stackoverflow question, in this case when there are a lot of nested loops. For an overview of other cases of recursion vs loops, check out this pdf.
There are three reasons why nested loops can be bad practice if used inappropriately: they decrease the readability of the code. they can reduce performance. they make debugging harder.
I recently wrote a recursive function to create all combinations of arrays. You would have to translate your data into an array of arrays that my function uses, but that shouldn't be difficult.
Anyway, here's the code with a runnable example:
var v = [['Miniors','Kadettes','Juniors', 'Seniors'], ['Boys','Girls','Men','Women'],['54kg - 62kg','64kg - 70kg','71kg - 78kg','79kg - 84kg']];
var combos = createCombinations(v);
for(var i = 0; i < combos.length; i++) {
document.getElementsByTagName("body")[0].innerHTML += combos[i] + "<br/>";
}
function createCombinations(fields, currentCombinations) {
//prevent side-effects
var tempFields = fields.slice();
//recursively build a list combinations
var delimiter = ' | ';
if (!tempFields || tempFields.length == 0) {
return currentCombinations;
}
else {
var combinations = [];
var field = tempFields.pop();
for (var valueIndex = 0; valueIndex < field.length; valueIndex++) {
var valueName = field[valueIndex];
if (!currentCombinations || currentCombinations.length == 0) {
var combinationName = valueName;
combinations.push(combinationName);
}
else {
for (var combinationIndex = 0; combinationIndex < currentCombinations.length; combinationIndex++) {
var currentCombination = currentCombinations[combinationIndex];
var combinationName = valueName + delimiter + currentCombination;
combinations.push(combinationName);
}
}
}
return createCombinations(tempFields, combinations);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With