Home > database >  How to group array of objects by certain prop and retain original object properties
How to group array of objects by certain prop and retain original object properties

Time:09-13

I have an array of objects, these objects have a property that I want to group by. So my goal is to produce a new array of objects where they have all the same properties with an additional property that consolidates all the "value" properties into an array.

Below is my input and desired output. How could I accomplish this ?

INPUT

[  {
        group_by_this_property: 1,
        value: 100,
        class: 'A',
      },
      {
        group_by_this_property: 1,
        value: 101,
        class: 'A',
      },
      {
        group_by_this_property: 1,
        value: 102,
        class: 'A',
      },
      {
        group_by_this_property: 2,
        value: 200,
        class: 'B',
      },
      {
        group_by_this_property: 2,
        value: 201,
        class: 'B',
      }
    ]

OUTPUT

[
  {
    group_by_this_property: 1,
    values: [100, 101, 102],
    class: 'A',
  },
  {
    group_by_this_property: 2,
    values: [200, 201],
    class: 'B',
  },
]

CodePudding user response:

You can group the items using a Map and return the values in the end as follows:

const data = [ { group_by_this_property: 1, value: 100, class: 'A' }, { group_by_this_property: 1, value: 101, class: 'A' }, { group_by_this_property: 1, value: 102, class: 'A' }, { group_by_this_property: 2, value: 200, class: 'B' }, { group_by_this_property: 2, value: 201, class: 'B' } ];

const res = [...
  data.reduce((map, { group_by_this_property, value, ...props }) => {
    const { values = [] } = map.get(group_by_this_property) ?? {};
    values.push(value);
    map.set(group_by_this_property, { ...props, group_by_this_property, values});
    return map;
  }, new Map)
  .values()
];

console.log(res);

CodePudding user response:

I can give you a couple of examples here. One using reduce

inputArr.reduce((acc, curr) => {
    const existingGroup = acc.find(item => item.group_by_this_property === curr.group_by_this_property);
    if (!existingGroup) {
        acc.push({
            ...curr,
            values: [curr.value]
        });
        delete curr.value;
        return acc;
    }

    existingGroup.values.push(curr.value);
    return acc;
}, [])

And another one with plain old for loop

const hashMap = {};
const res = [];
for (let index = 0; index < foo.length; index  ) {
    const element = inputArr[index];
    if(element.group_by_this_property in hashMap) {
        hashMap[element.group_by_this_property].values.push(element.value);
    } else {
        hashMap[element.group_by_this_property] = {
            ...element,
            values: [element.value]
        };
        delete hashMap[element.group_by_this_property].value;
        res.push(hashMap[element.group_by_this_property]);
    }
}

Why two? Well in terms of readability you can argue that first one is easier to read, and use. But the it becomes a bit complicated if your inputArr is large enough you will end up with O(n^2) which will impact performance of this algorithm.

Second one will do the same job in O(n) time. If performance is not an issue for you, or the data input is small enough, I would use the first example.

  • Related