1

Expected input:

const all = [
       {  "Attribute_Values" : [ "36", "38", "40" ],
          "Attribute" : "size"
       }, 
       {  "Attribute_Values" : [ "blue", "black" ],
          "Attribute" : "color"
       }
    ];

Expected output:

[ {size: '36', color: 'blue'},
  {size: '36', color: 'black'},
  {size: '38', color: 'blue'},
  {size: '38', color: 'black'}, 
  {size: '40', color: 'blue'},
  {size: '40', color: 'black'} ]
Chris Cousins
  • 1,862
  • 8
  • 15
kathir
  • 4,255
  • 2
  • 15
  • 25

3 Answers3

4

First generate an object with wanted keys and values, then take a recursive function which separates all key/value pairs and build a new cartesian product by iterating the values, if an array with objects call getCartesian again and build new objects.

This works for nested objects as well.

function getCartesian(object) {
    return Object.entries(object).reduce((r, [k, v]) => {
        var temp = [];
        r.forEach(s =>
            (Array.isArray(v) ? v : [v]).forEach(w =>
                (w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
                    temp.push(Object.assign({}, s, { [k]: x }))
                )
            )
        );
        return temp;
    }, [{}]);
}

var all = [{ Attribute_Values: ["36", "38", "40"], Attribute: "size" }, { Attribute_Values: ["blue", "black"], Attribute: "color" }],
    temp = Object.assign(...all.map(({ Attribute_Values, Attribute }) => ({ [Attribute]: Attribute_Values }))),
    cartesian = getCartesian(temp);

console.log(temp);
console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • I like your deconstruction of the main object to assign it to a new, more json-like object – Niche Aug 30 '18 at 21:07
1

I would go with a cartesian product generator which takes the attribute values, and while filling the result read the attribute name from the products current position. Generator is taken from here

const all = [
       {  "Attribute_Values" : [ "36", "38", "40" ],
          "Attribute" : "size"
       }, 
       {  "Attribute_Values" : [ "blue", "black" ],
          "Attribute" : "color"
       }
    ];

// Cartesian generator - copied from https://stackoverflow.com/a/44012184/3820185
function* cartesian(head, ...tail) {
  const remainder = tail.length > 0 ? cartesian(...tail) : [[]];
  for (let r of remainder) for (let h of head) yield [h, ...r];
}

let result = [], part, product, i;

for(product of cartesian(...all.map(i => i.Attribute_Values))) {
  part = {};
  for(i = 0; i < product.length; i++) part[all[i].Attribute] = product[i];
  result.push(part);
}

console.log(result);
wiesion
  • 2,349
  • 12
  • 21
0

You can iterate over the sizes array and then combine every size with every color by iterating over the colors array.

const all = [
       {  "Attribute_Values" : [ "36", "38", "40" ],
          "Attribute" : "size"
       }, 
       {  "Attribute_Values" : [ "blue", "black" ],
          "Attribute" : "color"
       }
    ];
    
 let results = [];
 
all[0].Attribute_Values.forEach(size => {
  all[1].Attribute_Values.forEach(color => {
    results.push({size: size, color: color});
   });
});

console.log(results);