从对象的嵌套数组和嵌套数组中过滤对象数组

时间:2020-03-11 18:07:27

标签: javascript arrays javascript-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" }
      ]
    }
  ]

我希望期望的输出是

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

我尝试了以下方式

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

我正在获得预期的输出,但是这里存在多个循环。有没有一种方法可以使我以更优化的方式编写解决方案。

4 个答案:

答案 0 :(得分:2)

您可以对嵌套属性采用分组功能,其中将传递映射,用于迭代的数组,组和值键。结果是一张地图,其中包含每个组的所有收集值。

稍后从地图上获取所有唯一值并构建新的对象数组。

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

答案 1 :(得分:1)

如果可以使用它们,Sets将在这里成为您的朋友:

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

使用此方法,每个要素数组和字段数组仅精确地迭代一次。

如果您不能使用Set,则可以使用js对象模拟它们的行为。目标是使用不需要再次迭代以找到唯一值的某些结构。

答案 2 :(得分:1)

首先构建一个值为Sets的对象。然后将集合的对象转换为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));

答案 3 :(得分:0)

以下功能即可完成

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: [] }
  ])
}

但是,您的对象结构相当混乱,您应该构建访问器函数,以从初始元素中提取信息,并使用一些辅助函数来填充结果对象。 无论如何,请在此处阅读有关“减少”功能的更多信息;) https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Array/reduce

相关问题