Search code examples
javascriptarraysobjectecmascript-2016

Group many arrays into one based on object properties


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));

Solution

  • 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