Как сгруппировать массив по свойству объекта с помощью Redu () - PullRequest
0 голосов
/ 14 апреля 2020

На основе массива я хочу создать новый массив, сгруппированный по свойству 'desc' содержащихся объектов. Вот так:

const sourceArray = [
  { id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
  { id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' }
  { id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' }
  { id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];
const targetArray = [
  { desc: 'foo', ids: [
    { id: 'id1', prop1: 'ignoreme', prop2: 'ignoreme' },
    { id: 'id2', prop1: 'ignoreme', prop2: 'ignoreme' }
  ]},
  { desc: 'bar', ids: [
    { id: 'id3', prop1: 'ignoreme', prop2: 'ignoreme' }
  ]},
  { desc: 'baz', ids: [
    { id: 'id4', prop1: 'ignoreme', prop2: 'ignoreme' }
  ]}
];

Полагаю, функция высшего порядка reduce() будет лучшим / современным / эффективным способом для достижения этой цели ... И если да, то как? Я немного застрял в моей голове ... Я нашел некоторые ответы на эту топи c, но я не могу адаптировать их к моей структуре массива: - (

Ответы [ 6 ]

1 голос
/ 14 апреля 2020

Вот еще один способ использования карты: массив JSON для группировки по ключу :

const sourceArray = [{"id":"id1","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id2","sourceDesc":"foo","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id3","sourceDesc":"bar","prop1":"ignoreme","prop2":"ignoreme"},{"id":"id4","sourceDesc":"baz","prop1":"ignoreme","prop2":"ignoreme"}];

const key = 'sourceDesc';

const arrayUniqueByKey1 = [...new Map(sourceArray.map(item =>
  [item[key], sourceArray.filter(x=>x[key] == item[key])]))
 /*remove following comment to get flat array*/ //.values()
];

console.log(arrayUniqueByKey1);

   /*OUTPUT Format
       [
  [
    "foo",
    [
      {
        "id": "id1",
        "sourceDesc": "foo",
        "prop1": "ignoreme",
        "prop2": "ignoreme"
      },
      {
        "id": "id2",
        "sourceDesc": "foo",
        "prop1": "ignoreme",
        "prop2": "ignoreme"
      }
    ]
  ]
]
   */
1 голос
/ 14 апреля 2020

Вы можете уменьшить массив до Map, используя sourceDesc в качестве ключа, а затем распространить итератор Map.values() обратно в массив:

const sourceArray = [
  { id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];

const result = [...
  sourceArray.reduce((r, { sourceDesc: desc, ...o }) => {
    if(!r.has(desc)) r.set(desc, { desc, ids: [] }); // add the group if doesn't exist

    r.get(desc).ids.push(o); // add the object to the group

    return r;
  }, new Map)
.values()]; // spread the Map's values to get an array

console.log(result);
1 голос
/ 14 апреля 2020

Вы можете использовать уменьшить, как это

const sourceArray = [
  { id: 'id1', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
  { id: 'id2', 'sourceDesc': 'foo', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
  { id: 'id3', 'sourceDesc': 'bar', 'prop1': 'ignoreme', 'prop2': 'ignoreme' },
  { 'id': 'id4', 'sourceDesc': 'baz', 'prop1': 'ignoreme', 'prop2': 'ignoreme' }
];

const final = sourceArray.reduce((op,{id,sourceDesc,prop1,prop2})=>{
  let key= sourceDesc
  op[key] = op[key] || {des:sourceDesc, ids:[]}
  op[key].ids.push({id,prop1,prop2})
  return op
},{})

console.log(Object.values(final))
1 голос
/ 14 апреля 2020

Вы можете получить желаемый результат, используя .reduce() вместе с Object.entries() и .map() методами:

const data = [
  { id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];

const reducer = (arr) => Object.entries(
  arr.reduce((r, { sourceDesc:desc, ...rest }) => {
    r[desc] = r[desc] || [];
    r[desc].push(rest);
    return r;
  }, {})
).map(([k, v]) => ({desc: k, ids: v}));

console.log(reducer(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
1 голос
/ 14 апреля 2020

Используя .reduce() и .find() комбинацию:

const sourceArray = [
  { id: 'id1', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id2', sourceDesc: 'foo', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id3', sourceDesc: 'bar', prop1: 'ignoreme', prop2: 'ignoreme' },
  { id: 'id4', sourceDesc: 'baz', prop1: 'ignoreme', prop2: 'ignoreme' }
];

const result = sourceArray.reduce((a, c) => {
  const found = a.find(e => e.desc === c.sourceDesc);
  
  if (found) found.ids.push({
    id: c.id,
    prop1: c.prop1,
    prop2: c.prop2
  });
  else a.push({
    desc: c.sourceDesc,
    ids: [{
      id: c.id,
      prop1: c.prop1,
      prop2: c.prop2
    }]
  });
  return a;
}, []);

console.log(result);
0 голосов
/ 14 апреля 2020

Мы можем сделать с forEach и строить объект с ключами как sourceDesc

const sourceArray = [
  { id: "id1", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
  { id: "id2", sourceDesc: "foo", prop1: "ignoreme", prop2: "ignoreme" },
  { id: "id3", sourceDesc: "bar", prop1: "ignoreme", prop2: "ignoreme" },
  { id: "id4", sourceDesc: "baz", prop1: "ignoreme", prop2: "ignoreme" }
];

const update = data => {
  const res = {};
  data.forEach(({ sourceDesc, ...item }) => {
    if (!res[sourceDesc]) {
      res[sourceDesc] = { desc: sourceDesc, ids: [] };
    }
    res[sourceDesc].ids.push(item);
  });
  return Object.values(res);
};

console.log(update(sourceArray));
...