Source: Core/arrayProduct.js

'use strict';

var flatten = require('./flatten');

/**
 * Find the "product" of a set of arrays, equivalent to the python one-liner: list(itertools.product(*pools)).
 * Eg. [[a,b,c], [d], [e,f]] => [[a,d,e], [a,d,f], [b,d,e], [b,d,f], [c,d,e], [c,d,f]].
 *
 * @param  {Array[]} pools The arrays of arrays.
 * @return {Array[]} The product of the arrays.
 */
function arrayProduct(pools) {
    // This code is based on the python equivalent at https://docs.python.org/2/library/itertools.html#itertools.product :
    // def product(*args):
    //     # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    //     pools = map(tuple, args)
    //     result = [[]]
    //     for pool in pools:
    //         result = [x+[y] for x in result for y in pool]
    //     for prod in result:
    //         yield tuple(prod)
    //
    // Note for A = [1, 2, 3], B = [10, 20] in python, [a + b for a in A for b in B] = [11, 21, 12, 22, 13, 23].
    // In js, A.map(function(a) { return B.map(function(b) { return a + b}) }) = [ [ 11, 21 ], [ 12, 22 ], [ 13, 23 ] ].
    // For A = [[]], B = [1], in python [a+[b] for a in A for b in B] = [[1]].
    // In js, A.map(function(a) { return B.map(function(b) { return a.concat(b); }) }) = [ [ [ 1 ] ] ].
    // So we need to flatten the js result to make it match itertool's.
    var result = [[]];
    pools.forEach(function(pool) {
        result = flatten(result.map(function(partialResult) {
            return pool.map(function(poolMember) {
                return partialResult.concat(poolMember);
            });
        }));
    });
    return result;
}

module.exports = arrayProduct;