Фильтровать массив объектов из вложенного массива и вложенного массива объектов - PullRequest
0 голосов
/ 11 марта 2020

У меня есть следующий массив объектов

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 ]

2 голосов
/ 12 марта 2020

Вы можете использовать функцию группировки для вложенных свойств, где передаются карта, массив для итерации, группа и ключи значений. В результате получается карта со всеми собранными значениями для каждой группы.

Позже получите все уникальные значения из карты и создайте новый массив объектов.

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 голос
/ 12 марта 2020

Сначала создайте объект со значениями Sets. Затем преобразуйте объект множеств в массив массива.

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));
1 голос
/ 11 марта 2020

Если вы можете использовать их, Комплекты будут вашими друзьями здесь:

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

Каждый массив объектов и массив полей повторяются только один раз с использованием этого подхода.

Если вы не можете использовать наборы, вы можете эмулировать их поведение, используя js объектов. Цель состоит в том, чтобы использовать некоторую структуру, которую не нужно повторять, чтобы найти уникальные значения.

0 голосов
/ 11 марта 2020

Следующая функция выполнит работу

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

...