(Updated answer in 2021)
This question is asking for the Cartesian product of several arrays and so the answers to that post will work.
In the special case where the arrays are all ranges of the same length, we can write a version like this:
function repeatProduct(length, repetitions) {
//--- Repeated Cartesian product of the array [0, 1, 2, ... length-1)]
const arr = new Array(repetitions).fill(0);
const r = [arr.slice()];
for (let i = 0; i < length ** repetitions - 1; i++) {
let j = repetitions - 1;
while (arr[j] === length - 1) {
arr[j] = 0;
j--;
}
arr[j]++;
r.push(arr.slice());
}
return r;
}
let cards = repeatedProduct(4, 4);
Or using map
and flatMap
, similar to this answer:
function repeatProduct(array, repetitions) {
let r = [[]];
while (repetitions--) {
r = r.flatMap(sub => array.map(item => [...sub, item]));
}
return r;
}
let cards = repeatProduct([0, 1, 2, 3], 4);
Original answer from 2013: A flexible solution is to start with a card with all the features set to zero, then use a for
loop which gets the next card in the sequence, within an outer while
loop that terminates when no more valid cards can be generated. (jsfiddle).
function createCards(dim) {
var card = [], cards = [];
while (card.length < dim.length) card.push(0);
while (card.length === dim.length) {
cards.push(card.slice(0));
for (var feature = 0; ++card[feature] === dim[feature]; feature++) {
card[feature] = 0;
}
}
return cards;
}
console.log(createCards([3, 3, 3, 3]));
Or similarly (but counting down instead of up)
function createCards(dim) {
var cards = [], card = dim.slice(0);
while (true) {
cards.push(card.slice(0));
for (var feature = dim.length - 1; !--card[feature]; card[feature] = dim[feature--]) {
if (feature < 1) return cards;
}
}
}
Alternatively, loop through the current set of cards, progressively adding variations of each feature.
function createCards(dim) {
var cards = [dim.slice(0)];
for (var feature = 0; feature < dim.length; feature++) {
var numberOfCards = cards.length;
for (var variation = dim[feature] - 1; variation > 0; variation--) {
for (var i = 0; i < numberOfCards; i++) {
var card = cards[i].slice(0);
card[feature] = variation;
cards.push(card);
}
}
}
return cards;
}
These should have the same result as mellamokb's answer.