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

时间:2019-07-10 21:46:10

标签: javascript arrays sorting object ecmascript-6

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

[
  {
    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")
  }
]

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

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

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

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

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

[
  [
    {
      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")
    }
  ]
]

2 个答案:

答案 0 :(得分:0)

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

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函数,只是保留了字符串日期以使代码段可执行。)

答案 1 :(得分:0)

我建议使用lodash

var ISODate = function(str) { return str };

var data = [
  {
    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")
  }
]

console.log(
  _.mapValues(
    _.groupBy(data, 'group'),
    function(item) { return _.orderBy(item, ['date'], ['asc']) }
  )
)

https://codepen.io/anon/pen/bPzmOr