1

I have an object. I want to loop through one of it's properties: itself an array of arrays which contain values. For every one of those values, I want to output an array containing a representative value from each of the child arrays, such that every possible combination of values will be output. Where there are more than one value in a child array, a max of 1 value at a time should be allowed. It's at this point that I think it should 'jump on' to the next one (and do the same for all others) but I'm not sure how. The results should look like this:

RABBIT: GREY, FURRY, BOUNCES, CUTE

RABBIT: WHITE, FURRY, BOUNCES, CUTE

RABBIT: RED, FURRY, BOUNCES, CUTE

RABBIT: GREY, FURRY, SCAMPERS, CUTE

RABBIT: WHITE, FURRY, SCAMPERS, CUTE

RABBIT: RED, FURRY, SCAMPERS, CUTE

The array (and it's child arrays) will have unknown lengths, so I've used the for loop. Here is the code so far:

window.onload = function (){
var myObject = {
        name: 'RABBIT',
        arrayOfValues : [
            ['GREY','WHITE','RED'],
            ['FURRY'],
            ['BOUNCES', 'SCAMPERS'],
            ['CUTE']
        ]
    };

var results = [];
for (i=0;i<myObject.arrayOfValues.length;i++){
    for (j=0; j<myObject.arrayOfValues[i].length;j++){
        if(myObject.arrayOfValues[i].length>1) {
            var currentProperty = myObject.arrayOfValues[i][j];
            myFunc();
        }
        else {
            var currentProperty = myObject.arrayOfValues[i][0];
            myFunc();
        };
    };
};

function myFunc(){
    results = results.concat(currentProperty);
    if (results.length == myObject.arrayOfValues.length){
    var finalResults = myObject.name + ': ' + results
    console.log(finalResults);
    };
};
};

PS - The form of the data is not set in stone, I just used an object for convenience.

Thanks, Paul

Selfish
  • 6,023
  • 4
  • 44
  • 63
Paul
  • 75
  • 9
  • 1
    It's kind of a side not, but I notice that you are passing the value currentProperty using whats called a global - a variable that is declared outside of the function. It is much easier and better to use arguments. – wedstrom Sep 17 '15 at 16:11

2 Answers2

3

You can make a recursive function call with an increasing index parameter, as well as a string to which you append the new part of the string and return.

var arrayOfArrays = [
  ['big', 'red'],
  ['red', 'yellow', 'blue'],
  ['dog', 'cat']
];

var strings = [];

function eachStep(string_so_far, array_index) {
  if (array_index < arrayOfArrays.length) {
    for (var i = 0; i < arrayOfArrays[array_index].length; i++) {
      var string_for_this_step = string_so_far + arrayOfArrays[array_index][i] + " ";
      var string_returned = eachStep(string_for_this_step, array_index+1);
      if (string_returned !== "") {
        strings.push(string_returned);
      }
    }
    return "";
  } else {
    return string_so_far;
  }
}

eachStep("", 0);

console.log(strings);
Robin James Kerrison
  • 1,727
  • 1
  • 15
  • 26
  • This is brilliant, I just tried it with some extra 'arrayOfArray's and it works, nice one Robin :) – Paul Sep 17 '15 at 16:26
2

Recursion is the native solution here:

// Object as described by question:
var myObject = {
    name: 'RABBIT',
    arrayOfValues: [
        ['GREY', 'WHITE', 'RED'],
        ['FURRY'],
        ['BOUNCES', 'SCAMPERS'],
        ['CUTE']
    ]
};

function permutations(arrays, current_array, idx, results) {
    // Init head and results in case this is the first iteration:
    idx = idx || 0;
    results = results || [];
    current_array = current_array || [];
    // If there's nothing more to add:
    if (arrays.length == idx) {
        results.push(current_array);
        return;
    }
    // Otherwise, iterate current level and concat values, while calling next level:
    arrays[idx].forEach(function(subArrayItem) {
        permutations(arrays, current_array.concat(subArrayItem), idx + 1, results)
    });
    return results;
}

The function above will return a set of arrays having all combinations, next is a helper function for printing:

// Helper method to print resulting arrays:
function print(obj) {
    var separator = "\n"
    var prefix = obj.name + ": ";
    // Joins the resulting sets with the prefix, and returns printable string:
    return prefix + permutations(obj.arrayOfValues).join(separator + prefix)
}

console.log(print(myObject));
Selfish
  • 6,023
  • 4
  • 44
  • 63
  • Great answer Nitai, and the comments help a lot to clarify what's going on. Thank you! It is interesting that you use forEach. I read more about forEach [here](http://stackoverflow.com/questions/9329446/for-each-over-an-array-in-javascript) – Paul Sep 17 '15 at 18:19
  • Thanks. I tend to prefer the callback styled `forEach()`. It makes the whole code more flexible and read able in my opinion, and in some cases, it's useful in separation to blocks, leaving the function in scope, and only invoking inside the loop. :) – Selfish Sep 17 '15 at 18:25