cartesian
Version:
Computes the cartesian product of arrays provided by an array or an object
85 lines (72 loc) • 1.83 kB
JavaScript
var extend = require('xtend/immutable');
// Public API
module.exports = cartesian;
/**
* Creates cartesian product of the provided properties
*
* @param {object|array} list - list of (array) properties or array of arrays
* @returns {array} all the combinations of the properties
*/
function cartesian(list)
{
var last, init, keys, product = [];
if (Array.isArray(list))
{
init = [];
last = list.length - 1;
}
else if (typeof list == 'object' && list !== null)
{
init = {};
keys = Object.keys(list);
last = keys.length - 1;
}
else
{
throw new TypeError('Expecting an Array or an Object, but `' + (list === null ? 'null' : typeof list) + '` provided.');
}
function add(row, i)
{
var j, k, r;
k = keys ? keys[i] : i;
// either array or not, not expecting objects here
Array.isArray(list[k]) || (typeof list[k] == 'undefined' ? list[k] = [] : list[k] = [list[k]]);
for (j=0; j < list[k].length; j++)
{
r = clone(row);
store(r, list[k][j], k);
if (i >= last)
{
product.push(r);
}
else
{
add(r, i + 1);
}
}
}
add(init, 0);
return product;
}
/**
* Clones (shallow copy) provided object or array
*
* @param {object|array} obj - object or array to clone
* @returns {object|array} - shallow copy of the provided object or array
*/
function clone(obj)
{
return Array.isArray(obj) ? [].concat(obj) : extend(obj);
}
/**
* Stores provided element in the provided object or array
*
* @param {object|array} obj - object or array to add to
* @param {mixed} elem - element to add
* @param {string|number} key - object's property key to add to
* @returns {void}
*/
function store(obj, elem, key)
{
Array.isArray(obj) ? obj.push(elem) : (obj[key] = elem);
}