-1

I'm working on an e-commerce website. I have to manage product variations. The REST API response looks something like this:

"variations": [
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "L"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "XXL"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "Azul"
      },
      {
        "name": "Talle",
        "valueName": "M"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "S"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "XL"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "Azul"
      },
      {
        "name": "Talle",
        "valueName": "S"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "M"
      }
    ]
  }
]

This JSON is inefficient for me to work on the frontend. It's difficult to group variations based on its type (name) and values (valueName) since they are on different "array of arrays".

The final result should be something like this:

variations: [
  {
    name: 'Color',
    values: ['Gris', 'Azul']
  },
  {
    name: 'Talle',
    values: ['S', 'M', 'L', 'XL', 'XXL']
  }
]

So far I've achieved this result:

[
  { name: "Color", values: ["GRIS"] },
  { name: "Talle", values: ["L"] },
  { name: "Color", values: ["GRIS"] },
  { name: "Talle", values: ["XXL"] },
  { name: "Color", values: ["Azul"] },
  { name: "Talle", values: ["M"] },
  { name: "Color", values: ["GRIS"] },
  { name: "Talle", values: ["S"] },
  { name: "Color", values: ["GRIS"] },
  { name: "Talle", values: ["XL"] },
  { name: "Color", values: ["Azul"] },
  { name: "Talle", values: ["S"] },
  { name: "Color", values: ["GRIS"] },
  { name: "Talle", values: ["M"] }
]

Based on this code:

let variations = this.$page.product.variations;
let newArr = [];

variations.forEach(variation => {
        newArr.push(
          Object.values(
            variation.attributeCombinations.reduce(
              (result, { name, valueName }) => {
                // Create new group
                if (!result[name]) {
                  result[name] = {
                    name,
                    values: []
                  };
                }
                // Append to group
                result[name].values.push(valueName);

                return result;
              },
              {}
            )
          )
        );
      });
return newArr.reduce((acc, cur) => acc.concat(cur));
brda
  • 21
  • 4
  • Your desired output has loss of information compared to the original structure. For instance, the original structure does not have the combination Azul-XL. This information cannot be derived from your desired output. Are you sure about this? – trincot Apr 18 '19 at 20:53
  • @trincot Yes! I had noticed that. However, for now, and the specific use case I will give to this functionality, it's not really a problem. Thank you though! – brda Apr 20 '19 at 14:21
  • So did any of the answers suit your needs? Or are you still looking for an answer? – trincot Apr 20 '19 at 14:23
  • Naga's answer was exactly what I needed. Thank you very much – brda Apr 20 '19 at 14:26

3 Answers3

0

You can use reduce to loop thru the array and summarize into an object. Use forEach to loop thru the attributeCombinations and construct the desired output. Use Object.values to convert the object into an array.

var variations = [{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"L"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"XXL"}]},{"attributeCombinations":[{"name":"Color","valueName":"Azul"},{"name":"Talle","valueName":"M"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"S"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"XL"}]},{"attributeCombinations":[{"name":"Color","valueName":"Azul"},{"name":"Talle","valueName":"S"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"M"}]}];

var result = Object.values(variations.reduce((c, v) => {
  v.attributeCombinations.forEach(({name,valueName}) => {
    c[name] = c[name] || {name,values: []}
    c[name].values.push(valueName);
  });
  return c;
}, {}));

console.log(result);

If you want unique values, you can use Set and add another loop to convert the Set object into an array.

var variations = [{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"L"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"XXL"}]},{"attributeCombinations":[{"name":"Color","valueName":"Azul"},{"name":"Talle","valueName":"M"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"S"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"XL"}]},{"attributeCombinations":[{"name":"Color","valueName":"Azul"},{"name":"Talle","valueName":"S"}]},{"attributeCombinations":[{"name":"Color","valueName":"GRIS"},{"name":"Talle","valueName":"M"}]}]

var result = Object.values(variations.reduce((c, v) => {
  v.attributeCombinations.forEach(({name,valueName}) => {
    c[name] = c[name] || {name,values: new Set}
    c[name].values.add(valueName);
  });
  return c;
}, {})).map(o => {
  o.values = [...o.values.values()]
  return o;
});

console.log(result);
Eddie
  • 26,593
  • 6
  • 36
  • 58
0

You can use the function reduce for grouping and the function Object.values for extracting the values.

The object Set provides a way to remove repeated values.

let variations = [   {     "attributeCombinations": [       {         "name": "Color",         "valueName": "GRIS"       },       {         "name": "Talle",         "valueName": "L"       }     ]   },   {     "attributeCombinations": [       {         "name": "Color",         "valueName": "GRIS"       },       {         "name": "Talle",         "valueName": "XXL"       }     ]   },   {     "attributeCombinations": [       {         "name": "Color",         "valueName": "Azul"       },       {         "name": "Talle",         "valueName": "M"       }     ]   },   {     "attributeCombinations": [       {         "name": "Color",         "valueName": "GRIS"       },       {         "name": "Talle",         "valueName": "S"       }     ]   },   {     "attributeCombinations": [       {         "name": "Color",         "valueName": "GRIS"       },       {         "name": "Talle",         "valueName": "XL"       }     ]   },   {     "attributeCombinations": [       {         "name": "Color",         "valueName": "Azul"       },       {         "name": "Talle",         "valueName": "S"       }     ]   },   {     "attributeCombinations": [       {         "name": "Color",         "valueName": "GRIS"       },       {         "name": "Talle",         "valueName": "M"       }     ]   } ];
let result = Object.values(variations.reduce((a, {attributeCombinations: combinations}) => {
  combinations.forEach(({name, valueName}) => {
    (a[name] || (a[name] = {name, values: new Set()})).values.add(valueName);
  });
  
  return a;
}, {}));

console.log(Array.from(result[0].values));// for understanding the object set
console.log(result);
.as-console-wrapper { min-height: 100%; }
Ele
  • 33,468
  • 7
  • 37
  • 75
  • I didn't know about the Set object. Your code is really clean! The result isn't exactly what I needed, but your help is much appreciated. Thank you! – brda Apr 20 '19 at 14:24
0

To achieve expected result, use below option of using reduce , forEach and index of each loop

  1. Loop through variations array
  2. For first index at position 0, push to Accumulator (acc)
  3. Use second loop using .forEach to loop through attributeCombinations
  4. Push valueNames to corresponding names- Color and Talle

var arr = {"variations": [
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "L"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "XXL"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "Azul"
      },
      {
        "name": "Talle",
        "valueName": "M"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "S"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "XL"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "Azul"
      },
      {
        "name": "Talle",
        "valueName": "S"
      }
    ]
  },
  {
    "attributeCombinations": [
      {
        "name": "Color",
        "valueName": "GRIS"
      },
      {
        "name": "Talle",
        "valueName": "M"
      }
    ]
  }
]
          }


console.log(arr.variations.reduce((acc, val, idx) => {
  val.attributeCombinations.forEach((v, i) => {
  if(idx === 0) {
    acc.push({name: v.name , valueName:  Array.of(v.valueName)})
  }else{
    i === 0 ? acc[0].valueName.push(v.valueName) : acc[1].valueName.push(v.valueName) 
  }
})
  return acc
},[]).map(v => v = {name :v.name,  valueName: [...new Set(v.valueName)]}));

codepen - https://codepen.io/nagasai/pen/ZZxVzp?editors=1010

Naga Sai A
  • 10,771
  • 1
  • 21
  • 40