Search code examples
javascriptarraysjavascript-objects

Filter array of objects from nested array and nested array of objects


I have the following array of object

const skus = [
    {
      id: 1,
      features: ["Slim"],
      fields: [
        { label: "Material", value: "Material1" },
        { label: "Type", value: "Type1" }
      ]
    },
    {
      id: 2,
      features: ["Cotton"],
      fields: [
        { label: "Material", value: "Material2" },
        { label: "Type", value: "Type2" }
      ]
    },
    {
      id: 3,
      features: ["Slim"],
      fields: [
        { label: "Material", value: "Material3" },
        { label: "Type", value: "Type1" }
      ]
    }
  ]

And i want the expected output to be

const output = [
    { label: "features", value: ["Slim", "Cotton"] },
    { label: "Material", value: ["Material1", "Material2", "Material3"] },
    { label: "Type", value: ["Type1", "Type2"] }
  ]

I tried the following way

const output = [];

  let featureArr = [];
  let fieldsArr = []
  skus.forEach(e => {
    e.features.forEach(f => {
      featureArr.push(f);
    });
    e.fields.forEach(f => {
      fieldsArr.push({ label: f.label, value: f.value });
    });
  });
  featureArr = _.uniq(featureArr);
  fieldsArr = _.uniqBy(fieldsArr, 'value')
  fieldsArr = _.groupBy(fieldsArr, 'label');

  output.push({ label: 'Features', value: featureArr })

  for (const k in fieldsArr) {
    let valArr = []
    valArr = fieldsArr[k].map(v => v.value)
    output.push({ label: k, value: valArr });
  }

I'm getting the expected output, but here multiple loops are present. Is there a way on how can i write the solution in more optimized way.


Solution

  • First Build an object with values as Sets. Then convert the object of sets into array of array.

    const skus = [
      {
        id: 1,
        features: ["Slim"],
        fields: [
          { label: "Material", value: "Material1" },
          { label: "Type", value: "Type1" }
        ]
      },
      {
        id: 2,
        features: ["Cotton"],
        fields: [
          { label: "Material", value: "Material2" },
          { label: "Type", value: "Type2" }
        ]
      },
      {
        id: 3,
        features: ["Slim"],
        fields: [
          { label: "Material", value: "Material3" },
          { label: "Type", value: "Type1" }
        ]
      }
    ];
    
    const update = data => {
      const res = {};
      data.forEach(item => {
        const features = res["features"] || new Set();
        item.features.forEach(fea => features.add(fea));
        res["features"] = features;
    
        item.fields.forEach(field => {
          const labels = res[field.label] || new Set();
          labels.add(field.value);
          res[field.label] = labels;
        });
      });
      return Object.keys(res).map(key => ({ label: key, value: [...res[key]] }));
    };
    
    console.log(update(skus));