如何对 JavaScript 对象的值求和?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16449295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 04:43:03  来源:igfitidea点击:

How to sum the values of a JavaScript object?

javascriptobjectjavascript-objects

提问by Jonathan Vanasco

I'd like to sum the values of an object.

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

I'm used to python where it would just be:

我已经习惯了 python 的位置:

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

The following code works, but it's a lot of code:

以下代码有效,但代码很多:

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)

Am i missing anything obvious, or is this just the way it is?

我是否遗漏了任何明显的东西,或者这就是它的方式?

采纳答案by Sirko

You could put it all in one function:

你可以把它全部放在一个函数中:

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()Object.keys()Array.reduce()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)}`);

But this seems to be way slower: jsperf.com

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

回答by Micha? Per?akowski

It can be as simple as that:

可以这么简单:

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

Quoting MDN:

引用 MDN:

The Object.values()method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...inloop (the difference being that a for-in loop enumerates properties in the prototype chain as well).

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

from Object.values()on MDN

来自Object.values()MDN

The reduce()method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.

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

from Array.prototype.reduce()on MDN

来自Array.prototype.reduce()MDN

You can use this function like that:

你可以像这样使用这个函数:

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


Note that this code uses some ECMAScript features which are not supported by some older browsers (like IE). You might need to use Babelto compile your code.

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

回答by Leon

If you're using lodash you can do something like

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

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

回答by Blender

A regular forloop is pretty concise:

常规for循环非常简洁:

var total = 0;

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

You might have to add in object.hasOwnPropertyif you modified the prototype.

object.hasOwnProperty如果您修改了原型,则可能需要添加。

回答by jbabey

Any reason you're not just using a simple for...inloop?

有什么理由不只是使用简单的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/

http://jsfiddle.net/vZhXs/

回答by Ricardo Magalh?es

Honestly, given our "modern times" I'd go with a functional programming approach whenever possible, like so:

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

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

Our accumulator acc, starting with a value of 0, is accumulating all looped values of our object. This has the added benefit of not depending on any internal or external variables; it's a constant function so it won't be accidentally overwritten... win for ES2015!

我们的 accumulator acc,从值 0 开始,正在累积我们对象的所有循环值。这具有不依赖于任何内部或外部变量的额外好处;它是一个常量函数,所以它不会被意外覆盖...... ES2015 获胜!

回答by Krishnadas PC

Now you can make use of reducefunction and get the sum.

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

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

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

回答by Ismael Soschinski

Use Lodash

使用 Lodash

 import _ from 'Lodash';
 
 var object_array = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}];
 
 return _.sumBy(object_array, 'c')
 
 // return => 9

回答by Sudam Dissanayake

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

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

alert(sum)

回答by Sudam Dissanayake

I am a bit tardy to the party, however, if you require a more robust and flexible solution then here is my contribution. If you want to sum only a specific property in a nested object/array combo, as well as perform other aggregate methods, then here is a little function I have been using on a React project:

我对聚会有点迟到,但是,如果您需要更强大和灵活的解决方案,那么这就是我的贡献。如果您只想对嵌套对象/数组组合中的特定属性求和,以及执行其他聚合方法,那么这里是我在 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;
}

It is recursive, non ES6, and it should work in most semi-modern browsers. You use it like this:

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

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

Parameter breakdown:

参数分解:

obj= either an object or an array
property= the property within the nested objects/arrays you wish to perform the aggregate method on
aggregate= the aggregate method (sum, min, max, or count)
shallow= can either be set to true/false or a numeric value
depth= should be left null or undefined (it is used to track the subsequent recursive callbacks)

OBJ=任一物体或阵列
属性=你想要进行聚合方法的嵌套的对象/数组内的属性
骨料=聚合方法(总和,最小值,最大值,或计数)
=可以被设置为真/ false 或数值
depth= 应保留为 null 或未定义(用于跟踪后续的递归回调)

Shallow can be used to enhance performance if you know that you will not need to search deeply nested data. For instance if you had the following array:

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

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

If you wanted to avoid looping through the otherData property since the value you are going to be aggregating is not nested that deeply, you could set shallow to true.

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