0

I know that, there are countless of questions about group by one property from an array of object. But what I want to do is a litte more specific:

const lists = [
{ groupKey: 'ABC', key: 'r8', timestamp: '2014', index: 2 },
{ groupKey: 'ABC', key: 'q8', timestamp: '2012', index: 0 }, 
{ groupKey: 'ABC', key: 'w8', timestamp: '2013', index: 1 },
{ groupKey: 'CDE', key: 'r7', timestamp: '2019', index: 0 } 
]

Result should be grouped by groupKey and sorted by index

(indexes here are iterators 0,1,2,3... so no need to actually be sorted but rather to be placed in a right order of an array. Example: array[index] = ... ).

This should look like:

{ 
  ABC: [
    {  key: 'q8', timestamp: '2012', index: 0 },
    {  key: 'w8', timestamp: '2013', index: 1 },
    {  key: 'r8', timestamp: '2014', index: 2 }
  ],
  CDE: [
    { key: 'r7', timestamp: '2019', index: 0 } 
  ]
}

I have tried to group by without sorting:

const result = lists.reduce((r, item) => {
      let { groupKey, ...rest } = item
      r[item.groupKey] = [...(r[item.groupKey] || []), rest]
      return r
    }, {})

And with sorting, not successful but you know what I mean:

const result = lists.reduce((r, item) => {
          let { groupKey, ...rest } = item
          r[item.groupKey][item.index] = rest //err: can not set property 2 of undefined
          return r
        }, {})

Any suggestions are appreciated

tru.d
  • 555
  • 2
  • 6
  • 23
tomen
  • 539
  • 7
  • 20
  • As noted in the duplicate question, it's much easier to sort first and then group: `_(data).sortBy('index').groupBy('groupKey').value()` – georg May 27 '19 at 12:18

5 Answers5

3

You could take the index directly without later sorting.

const
    lists = [{ groupKey: 'ABC', key: 'r8', timestamp: '2014', index: 2 }, { groupKey: 'ABC', key: 'q8', timestamp: '2012', index: 0 }, { groupKey: 'ABC', key: 'w8', timestamp: '2013', index: 1 }, { groupKey: 'CDE', key: 'r7', timestamp: '2019', index: 0 }],
    result = lists.reduce((r, { groupKey, ...rest }) => {
        r[groupKey] = r[groupKey] || [];
        r[groupKey][rest.index] = rest;
        return r
    }, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Try like this

const lists = [
{ groupKey: 'ABC', key: 'r8', timestamp: '2014', index: 2 },
{ groupKey: 'ABC', key: 'q8', timestamp: '2012', index: 0 }, 
{ groupKey: 'ABC', key: 'w8', timestamp: '2013', index: 1 },
{ groupKey: 'CDE', key: 'r7', timestamp: '2019', index: 0 } 
]

var groupBy = function(datas, key) {
  return datas.reduce(function(data, x) {
    var dKey = x[key];
    delete x[key];
    (data[dKey] = data[dKey] || []).push(x);
    
    return data;
  }, {});
};

console.log(groupBy(lists, 'groupKey'));
Syed mohamed aladeen
  • 6,507
  • 4
  • 32
  • 59
0

You're almost there, you just need to sort after the reduce is finished:

const lists = [{
    groupKey: 'ABC',
    key: 'r8',
    timestamp: '2014',
    index: 2
  },
  {
    groupKey: 'ABC',
    key: 'q8',
    timestamp: '2012',
    index: 0
  },
  {
    groupKey: 'ABC',
    key: 'w8',
    timestamp: '2013',
    index: 1
  },
  {
    groupKey: 'CDE',
    key: 'r7',
    timestamp: '2019',
    index: 0
  }
]
const result = lists.reduce((r, item) => {
  const { groupKey, ...rest } = item
  r[groupKey] = [...(r[groupKey] || []), rest];
  return r;
}, {})
Object.values(result).forEach((arr) => {
  arr.sort((a, b) => a.index - b.index);
});
console.log(result);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

You can first group by keys and then you need to sort based on index

const lists = [{ groupKey: 'ABC', key: 'r8', timestamp: '2014', index: 2 },{ groupKey: 'ABC', key: 'q8', timestamp: '2012', index: 0 }, { groupKey: 'ABC', key: 'w8', timestamp: '2013', index: 1 },{ groupKey: 'CDE', key: 'r7', timestamp: '2019', index: 0 } ]

// group by groupkey
let grouped = lists.reduce((op, inp) => {
  let groupKey = inp.groupKey
  op[groupKey] = op[groupKey] || []
  op[groupKey].push(inp)
  return op
},{})

// sort by index 
let output = Object.entries(grouped).reduce((op,[key,value]) => {
  value = value.sort((a,b)=> a.index-b.index)
  op[key] = value
  return op
},{})

console.log(output)
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
0

Try this:

const result  = lists.reduce((r, item) => {
      let { groupKey, ...rest } = item
      r[item.groupKey] = [...(r[item.groupKey] || []), rest];
      (r[item.groupKey]).sort((a, b) => a.index - b.index);
      return r
    }, {});
Sumit Ridhal
  • 1,359
  • 3
  • 14
  • 30