使用Underscore/Lodash进行分组和求和

23

我有这样的JSON:

[
  {
     platformId: 1,
     payout: 15,
     numOfPeople: 4
  },
  {
     platformId: 1,
     payout: 12,
     numOfPeople: 3

  },
  {
     platformId: 2,
     payout: 6,
     numOfPeople: 5

  },
  {
     platformId: 2,
     payout: 10,
     numOfPeople: 1
  },

]

我希望按照 platformId 分组,并计算 payoutnumOfPeople 的总和。

例如,我希望得到以下 JSON 结果:

[
  "1": {
     payout: 27,
     numOfPeople: 7
   },

  "2": {
     payout: 16,
     numOfPeople: 6
  }
] 
我尝试使用 underscore.js 的 _.groupBy 方法,分组很好用,但是我该如何获得对象属性值的总和,就像我上面演示的那样?

我尝试使用 underscore.js_.groupBy 方法,虽然分组效果不错,但我该如何获取对象属性值的总和,就像上面我所演示的那样呢?


你所说的“对象属性之和”具体是什么意思?你是想分别对每个对象的payoutnumOfPeople求和,还是分别对每个对象的payoutnumOfPeople进行单独求和? - Whymarrh
@Whymarrh 没错。即我想要 payouts 的总和和 numOfPeople 的总和。 - WelcomeTo
6个回答

45

这是一个与Underscore类似,但具有更多高级功能的 Lodash 解决方案。

const data = [{
    platformId: 1,
    payout: 15,
    numOfPeople: 4
  },
  {
    platformId: 1,
    payout: 12,
    numOfPeople: 3

  },
  {
    platformId: 2,
    payout: 6,
    numOfPeople: 5

  },
  {
    platformId: 2,
    payout: 10,
    numOfPeople: 1
  },
];

const ans = _(data)
  .groupBy('platformId')
  .map((platform, id) => ({
    platformId: id,
    payout: _.sumBy(platform, 'payout'),
    numOfPeople: _.sumBy(platform, 'numOfPeople')
  }))
  .value()

console.log(ans);
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>


提示:这使用了lodash的'seq'或链式功能,而不是静态函数。在文档中,这在'Seq'部分有解释。请参考https://lodash.com/docs/4.17.11#lodash。 - Simon_Weaver
如果您不熟悉lodash中的链式操作,特别是在尝试使用tree-shaking或lodash-es时,请阅读此文章https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba。 - Simon_Weaver

14

我尝试按照函数式编程的方式完成这个任务,结果如下

console.log(_.chain(data)
    .groupBy("platformId")
    .map(function(value, key) {
        return [key, _.reduce(value, function(result, currentObject) {
            return {
                payout: result.payout + currentObject.payout,
                numOfPeople: result.numOfPeople + currentObject.numOfPeople
            }
        }, {
            payout: 0,
            numOfPeople: 0
        })];
    })
    .object()
    .value());

我已经投了赞成票,但仍然返回一个数组的数组。你能把它转换成他想查看的最终结果吗? - Mohy Eldeen

7

以lodash单行代码的精神为基础

  _.map(_.groupBy(your_list, 'group_by'), (o,idx) => { return { id: idx, 
summed: _.sumBy(o,'sum_me') }})

@hardikbeladiya 这个已经测试过并且可行。我在生产环境中使用它没有任何问题。你认为逻辑有什么问题?Map不是在迭代,而是简单地映射你想要分组的值,其中参数的聚合是通过sumBy进行总计的... - Ryan Charmley

5

使用 underscore.js 的函数式编程方式(据我看来)相当不错:

var sum = function(t, n) { return t + n; };
_.mapObject(
    _.groupBy(data, 'platformId'),
    function(values, platformId) {
        return {
            payout: _.reduce(_.pluck(values, 'payout'), sum, 0),
            numOfPeople: _.reduce(_.pluck(values, 'numOfPeople'), sum, 0)
        };
    }
);

最干净和最直接的方法来做实际所要求的事情。 - Julian

4
您可以不使用Underscore来完成此操作:
var result = data.reduce(function(acc, x) {
  var id = acc[x.platformId]
  if (id) {
    id.payout += x.payout
    id.numOfPeople += x.numOfPeople
  } else {
    acc[x.platformId] = x
    delete x.platformId
  }
  return acc
},{})

但是为什么你想要一个带有数字键的对象呢?你可以将其转换回集合:
var toCollection = function(obj) {
  return Object.keys(obj)
    .sort(function(x, y){return +x - +y})
    .map(function(k){return obj[k]})
}

toCollection(result)

请注意,对象会被改变,因此如果您想保留原始数据,可能需要先克隆它们。

6
接受的答案,但并没有回答问题! - Mohy Eldeen
2
纯JS很糟糕,我认为。 - Alex78191
2
为什么你想要一个带有数字键的对象?因为在问题的背景下,这些ID可能是UUID或任何唯一的ID。它们也不能保证是连续的。因此,任何关于良好ID的假设都应该被放弃,将ID作为键再次成为一个很好的解决方案。 - George Pantazes

-1
//Input 
[{
  "platformId": 1,
  "payout": 15,
  "numOfPeople": 4
}, {
  "platformId": 1,
  "payout": 12,
  "numOfPeople": 3
}, {
  "platformId": 2,
  "payout": 6,
  "numOfPeople": 5
}, {
  "platformId": 2,
  "payout": 10,
  "numOfPeople": 1
}]


//Output
{
 "1": {
    "payout": 43,
    "numOfPeople": 13
 },
 "2": {
    "payout": 43,
    "numOfPeople": 13
 }
}


// Code
output = _.reduce(input, function(acc, val, key) {
  acc[val.platformId] = {
     payout: _.sum(a, 'payout'),
     numOfPeople: _.sum(a, 'numOfPeople')
   };
  return acc;
  }, {});

你能解释一下你用这个答案解决了什么问题吗? - jwbensley
刚刚尝试使用loadash将输出格式化为所需格式。 - Devank
2
以上解决方案中的 a 是什么意思?这段代码失败了,因为它是 undefined - Jeremy P. Beasley

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