使用Lodash对分组对象进行排序

3

我有以下对象数组:

[{
   id: 1,
   amount: 2000,
   date: "2018-01-31T00:00:00.000Z"
},{
   id: 2,
   amount: 3000,
   date: "2017-07-31T00:00:00.000Z"
},{
   id: 3,
   amount: 6000,
   date: "2018-01-31T00:00:00.000Z"
},{
   id: 4,
   amount: 7000,
   date: "2017-01-31T00:00:00.000Z"
},{
   id: 5,
   amount: 5000,
   date: "2017-03-31T00:00:00.000Z"
},{
   id: 6,
   amount: 3000,
   date: "2018-02-22T00:00:00.000Z"
},{
   id: 7,
   amount: 4500,
   date: "2017-01-31T00:00:00.000Z"
}]

我正在调用以下命令按年份和日期对对象进行分组:
_(data)
.groupBy(o => new Date(o.date).getFullYear() + '-' + new Date(o.date).getMonth())
.map(o1 => _(o1).map(o2 => o2.amount).sum())

代码以上给了我一个像[xx,yy,aaa,bbb,...]这样的总和数组。
现在,我需要确保这些数组中的值将被排序(2018-2的总和将是最先的,2017-1的总和将在最后)。
当结果包含按我上面描述的排序对象数组时,也会很好,每个对象还将包含期间键“年份-月份”以检测当前值。预期输出将是这样的:
[
  {period: "2018-2", amount:3000}, // sum of 2018-2
  {period: "2018-1", amount: 8000 }, // sum of 2018-1
  {period: "2017-7", amount: 3000} // sum of 2017-7
  {period: "2017-3", amount: 5000} // sum of 2017-3
  {period: "2017-1" amount: 11500} // sum of 2017-1
]

可以编辑此链接以获得所需结果吗?谢谢!

只用lodash吗?你能只使用原生的JavaScript吗? - Ele
如果有更简洁的解决方案,我会更喜欢。如果在原生JS中有一些优雅的方式,我也可以接受。 - stack001 stack001
但我希望在lodash中使用链式操作是可能的。 - stack001 stack001
为什么你想要使用lodash来链接它,当完全可以(而且更易于阅读)不使用lodash呢?@Ele的回答已经很好地解决了这个问题。 - Nicolas Gehlert
如果你真的想要链式调用它,你只需要调整你的 map 函数来返回你想要的对象,然后使用你的排序回调函数调用 .sort()。 - Nicolas Gehlert
@NicolasGehlert 我尝试编辑它并从映射对象返回,例如 {amount: xxx, period: "xxx" },但我的尝试都没有成功。 - stack001 stack001
3个回答

3
您可以使用函数reduce和函数Object.values来实现。 仅使用原始的JavaScript语言。

var data = [{   id: 1,   amount: 2000,   date: "2018-01-31T00:00:00.000Z"},{   id: 2,   amount: 3000,   date: "2017-07-31T00:00:00.000Z"},{   id: 3,   amount: 6000,   date: "2018-01-31T00:00:00.000Z"},{   id: 4,   amount: 7000,   date: "2017-01-31T00:00:00.000Z"},{   id: 5,   amount: 5000,   date: "2017-03-31T00:00:00.000Z"},{   id: 6,   amount: 3000,   date: "2018-02-22T00:00:00.000Z"},{   id: 7,   amount: 4500,   date: "2017-01-31T00:00:00.000Z"}];

var result = Object.values(data.reduce((a, c) => {
  var [year, month] = c.date.split('-');
  var key = `${year}-${+month}`;
  (a[key] || (a[key] = {period: key, amount: 0})).amount += c.amount;
  return a;
}, {})).sort((a, b) => b.period.localeCompare(a.period));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }


2

您可以获取分组数据并按升序排序(使用lodash的唯一可能方式)并反转顺序。

var data = [{ id: 1, amount: 2000, date: "2018-01-31T00:00:00.000Z" }, { id: 2, amount: 3000, date: "2017-07-31T00:00:00.000Z" },{ id: 3, amount: 6000, date: "2018-01-31T00:00:00.000Z" }, { id: 4, amount: 7000, date: "2017-01-31T00:00:00.000Z" }, { id: 5, amount: 5000, date: "2017-03-31T00:00:00.000Z" }, { id: 6, amount: 3000, date: "2018-02-22T00:00:00.000Z" }, { id: 7, amount: 4500, date: "2017-01-31T00:00:00.000Z" }],
    result = _(data)
        .groupBy(o => o.date.slice(0, 7))
        .map((array, sort) => ({ sort, date: sort.split('-').map(Number).join('-'), amount: _.sumBy(array, 'amount') }))
        .sortBy('sort')
        .reverse()
        .map(({ date, amount }) => ({ date, amount }))
        .value();


console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>


可以进行比较编辑吗?因为当我使用另一种选项来连接日期时,例如年份+“-”+月份(没有零填充),对于11和2这样的数字就无法正常工作。 - stack001 stack001
@stack001stack001,是的,你可以将数字拆分、映射并用短横线连接起来,请参见编辑。 - Nina Scholz
还是不起作用,请检查一下这个链接:https://jsfiddle.net/aLz38yet/1/,我使用了您的代码和不同的数据。结果是2018-2在2018-11之前。 - stack001 stack001
不带前导零的字符串排序会返回错误的顺序。解决方案可以是重新映射或使用不同的排序函数来重新排序。 - Nina Scholz

1
使用lodash,您可以首先进行groupBy操作,然后对条目进行排序,最后将这些条目map成带有每个期间的periodamount总和的对象。

const data = [{"id":1,"amount":2000,"date":"2018-01-31T00:00:00.000Z"},{"id":2,"amount":3000,"date":"2017-07-31T00:00:00.000Z"},{"id":3,"amount":6000,"date":"2018-01-31T00:00:00.000Z"},{"id":4,"amount":7000,"date":"2017-01-31T00:00:00.000Z"},{"id":5,"amount":5000,"date":"2017-03-31T00:00:00.000Z"},{"id":6,"amount":3000,"date":"2018-02-22T00:00:00.000Z"},{"id":7,"amount":4500,"date":"2017-01-31T00:00:00.000Z"}]

const result = _.chain(data)
  .groupBy(({date}) => {
    const d = new Date(date)
    return d.getFullYear() + '-' + (d.getMonth() + 1)
  })
  .entries()
  .sort(([a], [b]) => b.localeCompare(a))
  .map(([period, arr]) =>  ({period, amount: _.sumBy(arr, ({amount}) => amount)}))

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>


感谢帮助我!但是 Nina 的解决方案看起来更清晰,所以我更喜欢她的,但还是非常感谢。 - stack001 stack001

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接