如何聚合对象属性? [英] How to aggregate objects properties?

查看:57
本文介绍了如何聚合对象属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有这样的对象(或类似的):

If I have an object like this (or similar):

sales = { 
    obs1:{
        Sales1:{
            Region:"North", Value: 200}, 
        Sales2:{
            Region:"South", Value:100}}, 
    obs2:{
        Sales1:{
            Region:"North", Value: 50}, 
        Sales2:{
            Region:"South", Value:20}
    }
}

我如何汇总属性的总和 Value by Region ?答案可以是纯JavaScript或库。

How could I aggregate the sum of the property Value by Region? Answers could be in pure JavaScript or a library.

最终结果应与此类似:

totals = {North: 250, South:120}


推荐答案

正如其他人指出的那样,没有内置的JavaScript函数可以做到这一点(有一些高阶函数,如 map ,但不足以完成任务) 。但是,某些库(如 Underscore.js )提供了许多实用程序来简化此类任务。

As others pointed out, there's no built-in JavaScript functions to do that (there are a few high-order functions like map, but not enough for the task). However, some libraries such as Underscore.js provide many utilities to simplify this kind of task.

var totals = _
    .chain(sales) // Wraps up the object in an "underscore object",
                  // so methods can be chained
    // First: "flatten" the sales
    .map(function(v) { 
        return _
            .chain(v)
            .map(function(v2) {
                return v2;
            })
            .value(); 
    })
    .flatten()
    // Second: group the sales by region
    .groupBy('Region')
    // Third: sum the groups and create the object with the totals
    .map(function(g, key) {
        return {
            type: key, 
            val: _(g).reduce(function(m, x) {
                return m + x.Value;
            }, 0)
        };
    })
    .value(); // Unwraps the "underscore object" back to a plain JS object

来源:这个答案在SOpt

这个答案假定结构您的数据是已知的 - 与其他答案相反,后者侧重于概括结构。虽然上面的代码可以自己推广,但是删除硬编码的 Region Value 并将嵌套级别改为其他两个以及聚合函数除了sum之外的其他东西 - 只要叶子包含你想要分组的属性和你想要聚合的值。

This answer assumes the structure of your data is known - contrary to the other answers, which focus on generalizing the structure. Though the code above can be generalized itself, by removing the hardcoded Region and Value and varying the nesting level to something other than two and the aggregation function to something other than sum - as long as the leaves contain both a property you want to group by, and a value you want to aggregate.

function aggregate(object, toGroup, toAggregate, fn, val0) {
    function deepFlatten(x) {
        if ( x[toGroup] !== undefined ) // Leaf
            return x;
        return _.chain(x)
                .map(function(v) { return deepFlatten(v); })
                .flatten()
                .value();
    }

    return _.chain(deepFlatten(object))
            .groupBy(toGroup)
            .map(function(g, key) {
                return {
                    type: key,
                    val: _(g).reduce(function(m, x) {
                        return fn(m, x[toAggregate]);
                    }, val0 || 0)
                };
            })
            .value();
}

它的调用方式如下:

function add(a,b) { return a + b; }
var totals = aggregate(sales, "Region", "Value", add);

另一个例子(按地区查找最小值):

Another example (finds minimum value by region):

function min(a,b) { return a < b ? a : b; }
var mins = aggregate(sales, "Region", "Value", min, 999999);

这篇关于如何聚合对象属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆