I have an object of the following form (simplified test case below)
var test = { shirts: { sizes: ['large', 'medium'] ,colors:['red', 'blue'] } , trousers: { type: ['formal', 'casual'] , pattern: ['plaid', 'stripes'] } };
I want to create a Cartesian product of properties so that the output is an array of the following form:
// desired output [ {shirts:{sizes:'large', color:'red'}, trousers:{type:'formal', pattern:'plaid'}} ,{shirts:{sizes:'large', color:'red'}, trousers:{type:'formal', pattern:'stripes'}} ,{shirts:{sizes:'large', color:'red'}, trousers:{type:'casual', pattern:'plaid'}} , {shirts:{sizes:'large', color:'red'}, trousers:{type:'casual', pattern:'stripes'}} ,{shirts:{sizes:'large', color:'blue'}, trousers:{type:'formal', pattern:'plaid'}} ..... and so on ]
How can i achieve this? I developed the following code (based on modifying the code for the Cartesian product of an array from another SO message), but it looks like I'm getting attached to nodes trying to get this to work.
function myCartesianProduct(input, current) { if (!input) { return []; } var head = input[Object.keys(input)[0]]; var tail = objSlice(input); var output = []; for (var key in head) { for (var i = 0; i < head[key].length; i++) { var newCurrent = copy(current); newCurrent[key] = head[key][i]; if (Object.keys(tail).length) { //if tail.length var productOfTail = myCartesianProduct(tail, newCurrent); output = output.concat(productOfTail); } else { output.push(newCurrent); } } } return output; } function objSlice(obj) { var slicedObj = angular.copy(obj); // copy object using angularJs copy method delete slicedObj[Object.keys(slicedObj)[0]]; //delete the first key return slicedObj; }; function copy(obj) { var res = {}; for (var p in obj) res[p] = obj[p]; return res; } console.log(myCartesianProduct(test));
Thanks in advance for your help!