Javascript - Группировка по одному свойству объекта в массиве объектов

Я знаю, что существует бесчисленное множество вопросов о группировке по одному свойству из массива объекта. Но я хочу сделать кое-что более конкретное:

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 } 
]

Результат должен быть сгруппирован по groupKey и отсортирован по индексу.

(индексы здесь - это итераторы 0,1,2,3 ... поэтому нет необходимости в сортировке, а следует размещать их в правильном порядке массива. Пример: array [index] = ...).

Это должно выглядеть так:

{ 
  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 } 
  ]
}

Я попытался сгруппировать без сортировки:

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

И с сортировкой не удалось, но вы понимаете, о чем я:

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
        }, {})

Любые предложения приветствуются


person tomen    schedule 27.05.2019    source источник
comment
Как отмечено в повторяющемся вопросе, намного проще сначала отсортировать, а затем сгруппировать: _(data).sortBy('index').groupBy('groupKey').value()   -  person georg    schedule 27.05.2019


Ответы (5)


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

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; }

person Nina Scholz    schedule 27.05.2019

Вы почти у цели, вам просто нужно отсортировать после завершения reduce:

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

person CertainPerformance    schedule 27.05.2019

Вы можете сначала сгруппировать по ключам, а затем вам нужно отсортировать по индексу

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)

person Code Maniac    schedule 27.05.2019

Попробуйте вот так

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

person Syed mohamed aladeen    schedule 27.05.2019

Попробуй это:

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
    }, {});
person Sumit Ridhal    schedule 27.05.2019