如何对对象数组进行分组和排序?

问题描述:

我有一个对象数组,我必须对其进行分组和排序:

I've got an object array which I have to group and sort:

[
  {
    id: 123,
    group: 'abc',
    metadata: {
      name: 'tom'
    },
    date: ISODate("2019-07-08T20:33:40.475Z")
  },
  {
    id: 456,
    group: 'def',
    metadata: {
      name: 'bob'
    },
    date: ISODate("2019-07-08T20:33:40.475Z")
  },
  {
    id: 789,
    group: 'def',
    metadata: {
      name: 'bob'
    },
    date: ISODate("2019-07-10T20:33:40.475Z")
  },
  {
    id: 234,
    group: 'ghi',
    metadata: {
      name: 'frank'
    },
    date: ISODate("2019-07-10T20:33:40.475Z")
  },
  {
    id: 567,
    group: 'abc',
    metadata: {
      name: 'tom'
    },
    date: ISODate("2019-07-10T20:33:40.475Z")
  }
]

首先,我需要按组值对元素进行分组,然后按日期对此分组数组中的元素进行排序.

Firstly I need to group the elements by the group value, then I need to sort the elements of this grouped array by date.

对于分组,我尝试了以下方法:

For grouping I've tried this:

const result = array.reduce(function (r, a) {
    r[a.group] = r[a.group] || [];
    r[a.group].push(a);
    return r;
}, Object.create(null));

但是结果与预期不符,并且元素没有按日期排序.

But the result is not as expected and the elements are not sorted by date.

结果可能/应该看起来像这样:

The result could/should look something like this:

[
  [
    {
      id: 123,
      group: 'abc',
      metadata: {
        name: 'tom'
      },
      date: ISODate("2019-07-08T20:33:40.475Z")
    },
    {
      id: 567,
      group: 'abc',
      metadata: {
        name: 'tom'
      },
      date: ISODate("2019-07-10T20:33:40.475Z")
    }
  ],
  [
    {
      id: 456,
      group: 'def',
      metadata: {
        name: 'bob'
      },
      date: ISODate("2019-07-08T20:33:40.475Z")
    },
    {
      id: 789,
      group: 'def',
      metadata: {
        name: 'bob'
      },
      date: ISODate("2019-07-10T20:33:40.475Z")
    }
  ],
  [
    {
      id: 234,
      group: 'ghi',
      metadata: {
        name: 'frank'
      },
      date: ISODate("2019-07-10T20:33:40.475Z")
    }
  ]
]

使用 reduce 对值进行分组,并使用 map sort 对它们进行排序/code>也是由于嵌套的数组结构.

Use reduce to group the values, and sort to sort them, using map as well due to the nested array structure.

const arr = [{id:123,group:'abc',metadata:{name:'tom'},date:"2019-07-08T20:33:40.475Z"},{id:456,group:'def',metadata:{name:'bob'},date:"2019-07-08T20:33:40.475Z"},{id:789,group:'def',metadata:{name:'bob'},date:"2019-07-10T20:33:40.475Z"},{id:234,group:'ghi',metadata:{name:'frank'},date:"2019-07-10T20:33:40.475Z"},{id:567,group:'abc',metadata:{name:'tom'},date:"2019-07-10T20:33:40.475Z"}];
const res = Object.values(arr.reduce((a, { group, ...r }) => {
  (a[group] = a[group] || []).push({ group, ...r });
  return a;
}, {})).map(e => e.sort(({ date: a }, { date: b }) => new Date(a) - new Date(b)));

console.log(res);

.as-console-wrapper { max-height: 100% !important; top: auto; }

(我取出了 ISODate 函数,只是保留了字符串日期以使代码段可执行.)

(I've taken out the ISODate function and just kept the string date to make the snippet executable.)