如何对JavaScript对象的值求和?


86

我想对一个对象的值求和。

我习惯了python会在哪里:

sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed =  sum(sample.itervalues())     

以下代码可以工作,但是有很多代码:

function obj_values(object) {
  var results = [];
  for (var property in object)
    results.push(object[property]);
  return results;
}

function list_sum( list ){
  return list.reduce(function(previousValue, currentValue, index, array){
      return previousValue + currentValue;
  });
}

function object_values_sum( obj ){
  return list_sum(obj_values(obj));
}

var sample = { a: 1 , b: 2 , c:3 };
var summed =  list_sum(obj_values(a));
var summed =  object_values_sum(a)

我是否遗漏了任何明显的东西,或者只是这样?

Answers:


73

您可以将其全部放在一个函数中:

function sum( obj ) {
  var sum = 0;
  for( var el in obj ) {
    if( obj.hasOwnProperty( el ) ) {
      sum += parseFloat( obj[el] );
    }
  }
  return sum;
}
    
var sample = { a: 1 , b: 2 , c:3 };
var summed = sum( sample );
console.log( "sum: "+summed );


为了方便起见,这是另一个使用Object.keys()和的实现Array.reduce()(浏览器支持不再是大问题):

function sum(obj) {
  return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
}
let sample = { a: 1 , b: 2 , c:3 };

console.log(`sum:${sum(sample)}`);

但这似乎要慢得多:jsperf.com


返回总和+ parseFloat(OBJ [键] || 0)来检查falsey或空/空值
SUMIT

1
突出解决方案之间的性能差异的出色工作。尽管Object.keys().reduce外观看起来更加优雅,但速度却慢了60%。
micnguyen

101

可以这么简单:

const sumValues = obj => Object.values(obj).reduce((a, b) => a + b);

报价MDN:

Object.values()方法以for...in循环提供的顺序返回给定对象自己的可枚举属性值的数组(区别是for-in循环也枚举原型链中的属性)。

来自Object.values()MDN

reduce()方法对一个累加器和数组的每个值(从左到右)应用一个函数以将其减小为单个值。

来自Array.prototype.reduce()MDN

您可以像这样使用此功能:

sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5

请注意,此代码使用某些早期浏览器(如IE)不支持的ECMAScript功能。您可能需要使用Babel来编译代码。


3
这需要您仅拉一个60K的库使其具有Object.values(),该库将在for除Firefox之外的所有浏览器上填充一个循环。即使没有polyfill,它也比常规for循环慢4倍。
Blender

10
@Blender如果要使用任何新的ECMAScript功能并且仍支持较旧的浏览器,则无论如何都需要使用Babel 。此外,例如,如果有人在两年后​​访问了这个问题,那么现代的浏览器可能会Object.values()在那之前实施。
米哈尔Perłakowski

公认的答案具有非常相似的方法,但是传递给该函数的功能reduce似乎更加简单。您是否故意删除了分析?
Cerbrus

@Cerbrus我假设该对象中的所有值都是数字。
米哈尔Perłakowski

12
@Blender看来我是对的-一年半过去了,并且Object.values()得到所有现代浏览器的支持
米哈尔Perłakowski

25

如果您使用lodash,则可以执行以下操作

_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 })) 

20

常规for循环非常简洁:

var total = 0;

for (var property in object) {
    total += object[property];
}

object.hasOwnProperty如果修改了原型,则可能必须添加。


14

老实说,鉴于我们的“现代时代”,我会尽可能采用一种函数式编程方法,例如:

const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);

acc从0开始的累加器正在累加对象的所有循环值。这具有不依赖于任何内部或外部变量的额外好处。这是一个常量函数,因此不会被意外覆盖...赢得ES2015!


12

有什么理由不只是使用简单的for...in循环?

var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;

for (var key in sample) {
    summed += sample[key];
};

http://jsfiddle.net/vZhXs/


11

现在,您可以使用reduce函数并获取总和。

const object1 = { 'a': 1 , 'b': 2 , 'c':3 }

console.log(Object.values(object1).reduce((a, b) => a + b, 0));


1

我对聚会有点迟疑,但是,如果您需要一个更强大,更灵活的解决方案,那么这就是我的贡献。如果您只想对嵌套对象/数组组合中的特定属性求和,并执行其他聚合方法,那么这是我在React项目上一直使用的一个小功能:

var aggregateProperty = function(obj, property, aggregate, shallow, depth) {
    //return aggregated value of a specific property within an object (or array of objects..)

    if ((typeof obj !== 'object' && typeof obj !== 'array') || !property) {
        return;
    }

    obj = JSON.parse(JSON.stringify(obj)); //an ugly way of copying the data object instead of pointing to its reference (so the original data remains unaffected)
    const validAggregates = [ 'sum', 'min', 'max', 'count' ];
    aggregate = (validAggregates.indexOf(aggregate.toLowerCase()) !== -1 ? aggregate.toLowerCase() : 'sum'); //default to sum

    //default to false (if true, only searches (n) levels deep ignoring deeply nested data)
    if (shallow === true) {
        shallow = 2;
    } else if (isNaN(shallow) || shallow < 2) {
        shallow = false;
    }

    if (isNaN(depth)) {
        depth = 1; //how far down the rabbit hole have we travelled?
    }

    var value = ((aggregate == 'min' || aggregate == 'max') ? null : 0);
    for (var prop in obj) {
        if (!obj.hasOwnProperty(prop)) {
            continue;
        }

        var propValue = obj[prop];
        var nested = (typeof propValue === 'object' || typeof propValue === 'array');
        if (nested) {
            //the property is an object or an array

            if (prop == property && aggregate == 'count') {
                value++;
            }

            if (shallow === false || depth < shallow) {
                propValue = aggregateProperty(propValue, property, aggregate, shallow, depth+1); //recursively aggregate nested objects and arrays
            } else {
                continue; //skip this property
            }
        }

        //aggregate the properties value based on the selected aggregation method
        if ((prop == property || nested) && propValue) {
            switch(aggregate) {
                case 'sum':
                    if (!isNaN(propValue)) {
                        value += propValue;
                    }
                    break;
                case 'min':
                    if ((propValue < value) || !value) {
                        value = propValue;
                    }
                    break;
                case 'max':
                    if ((propValue > value) || !value) {
                        value = propValue;
                    }
                    break;
                case 'count':
                    if (propValue) {
                        if (nested) {
                            value += propValue;
                        } else {
                            value++;
                        }
                    }
                    break;
            }
        }
    }

    return value;
}

它是递归的,非ES6,它应可在大多数半现代的浏览器中使用。您可以这样使用它:

const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');

参数明细:

obj =对象或数组
属性=要在嵌套对象/数组中执行聚合方法的属性=
聚合=聚合方法(总和,最小,最大或计数)
=可以设置为true /假或数值
深度 =应该保留为null或未定义(用于跟踪后续的递归回调)

如果您知道不需要搜索深度嵌套的数据,则可以使用Shallow来提高性能。例如,如果您具有以下数组:

[
    {
        id: 1,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 2,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 3,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    ...
]

如果要避免循环遍历otherData属性,因为要聚合的值没有嵌套那么深,则可以将shallow设置为true。



1

let prices = {
  "apple": 100,
  "banana": 300,
  "orange": 250
};

let sum = 0;
for (let price of Object.values(prices)) {
  sum += price;
}

alert(sum)


0

我在尝试解决类似问题时遇到了来自@jbabey的解决方案。稍加修改,我就对了。在我的情况下,对象键是数字(489)和字符串(“ 489”)。因此,为了解决这个问题,每个键都被解析。以下代码有效:

var array = {"nR": 22, "nH": 7, "totB": "2761", "nSR": 16, "htRb": "91981"}
var parskey = 0;
for (var key in array) {
    parskey = parseInt(array[key]);
    sum += parskey;
};
return(sum);


0

我们可以使用in关键字迭代对象并且可以执行任何算术运算。

// input
const sample = {
    'a': 1,
    'b': 2,
    'c': 3
};

// var
let sum = 0;

// object iteration
for (key in sample) {
    //sum
    sum += (+sample[key]);
}
// result
console.log("sum:=>", sum);


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.