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

蹲街弑〆低调 提交于 2020-05-17 06:59:06

问题


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.


回答1:


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



回答2:


You could take a grouping function for nested properties, where a map, an array for iterating, group and value keys are handed over. The result is a map with all collected values for each group.

Later get all unique values from the map and build a new array of objects.

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" }] }],
    getGrouped = (map, array, key, value) => array.reduce((m, o) =>
        m.set(o[key], [...(m.get(o[key]) || []), o[value]]), map),
    result = Array.from(
        skus.reduce((m, o) =>
            getGrouped(
                m.set('features', [...(m.get('features') || []), ...o.features]),
                o.fields,
                'label',
                'value'
            ),
            new Map
        ),
        ([label, value]) => ({ label, value: [...new Set(value)] })
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }



回答3:


If you can use them, Sets will be your friend here:

//data
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" }]}];

//solution
const output = Object.entries(skus.reduce((map,sku) => {
  sku.features.forEach(feat => map.features.add(feat));
  sku.fields.forEach(field => (map[field.label] = (map[field.label] || new Set()).add(field.value)));
  return map;
}, {features: new Set()})).map(([label, set]) => ({label, value: Array.from(set)}));

//display
console.log(output);

Each feature array and field array only get iterated exactly once using this approach.

If you can't use Sets, you can emulate their behavior using js objects. The goal is to use some structure that doesn't need to be iterated again to find unique values.




回答4:


The following function will do the job

const fn = (array) => {
  return array.reduce((result, element) => {
    const features = result[0].value
    const feature = element.features[0]
    if (!features.includes(feature)) {
      features.push(feature)
    }
    const materials = result[1].value
    const material = element.fields[0].value
    if (!materials.includes(material)) {
      materials.push(material)
    }
    const types = result[2].value
    const type = element.fields[1].value
    if (!types.includes(type)) {
      types.push(type)
    }
    return result
  }, [
    { label: 'features', value: [] },
    { label: 'Material', value: [] },
    { label: 'Type', value: [] }
  ])
}

BUT, your object structure is quite messy, you should likely build accessor functions that extract information from your initial elements, and use some helper functions to populate your result object. Anyway, read more about the 'reduce' function used here ;) https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce



来源:https://stackoverflow.com/questions/60642147/filter-array-of-objects-from-nested-array-and-nested-array-of-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!