Search code examples
javascriptecmascript-6underscore.jslodash

groupBy and sortBy an array of object in native ES6


We have an array of objects and we need to group these objects by group ID.

Then we need to obtain an array of array with sorted groups by timestamp.

This is the initial collection:

const arr = [
  {id: 'id1', group: '123', timestamp: 222},
  {id: 'id2', group: '123', timestamp: 999 },
  {id: 'id3', group: '456', timestamp: 333 },
  {id: 'id4', group: '789', timestamp: 111 },
  {id: 'id5', group: '554', timestamp: 555 },
];

The result we try to obtain is:

result = [
  [
    {id: 'id4', group: '789', timestamp: 111 }, 
  ],
  [
    {id: 'id1', group: '123', timestamp: 222},
    {id: 'id2', group: '123', timestamp: 999 },
  ],
  [
    {id: 'id3', group: '456', timestamp: 333 },
  ],
  [
    {id: 'id5', group: '554', timestamp: 555 },
  ]
]

We achieved that using Underscore.js but we are looking for a solution using native javascript and we struggled to pass from a reduced object to an array of array.

var groups = _(arr).chain()
    .groupBy("group")
    .sortBy((data) => _.first(data).timestamp)
    .value();

https://jsfiddle.net/tdsow1ph/

We tried to first group the items using such a method:

const groupBy = (arr, propertyToGroupBy) => {
    return arr.reduce((groups, item) => {
      const val = item[propertyToGroupBy];

      groups[val] = groups[val] || [];
      groups[val].push(item);

      return groups;
    }, {});
  }

But we obtain an unsortable object. So we need to convert that into array of array but we struggle to do that then apply sorting on the timestamp value.


Solution

  • You can use reduce() to group the array into an object using the group as the key. Use Object.values() to convert the object into an array.

    const arr = [{"id":"id1","group":"123","timestamp":222},{"id":"id2","group":"123","timestamp":999},{"id":"id3","group":"456","timestamp":333},{"id":"id4","group":"789","timestamp":111},{"id":"id5","group":"554","timestamp":555}];
    
    var result = Object.values(arr.reduce((c, v) => {
      c[v.group] = c[v.group] || [];
      c[v.group].push(v);
      return c;
    }, {}));
    
    
    console.log(result);

    With sort()

    const arr = [{"id":"id4","group":"789","timestamp":111},{"id":"id1","group":"123","timestamp":222},{"id":"id3","group":"456","timestamp":333},{"id":"id5","group":"554","timestamp":555},{"id":"id2","group":"123","timestamp":999}]
    
    var result = Object.values(
      arr
      .sort((a, b) => a.timestamp - b.timestamp)
      .reduce((c, v) => {
        c[v.group] = c[v.group] || [];
        c[v.group].push(v);
        return c;
      }, {})
    );
    
    console.log(result);