简体   繁体   English

如何对 JavaScript 对象的值求和?

[英]How to sum the values of a JavaScript object?

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?我是否遗漏了任何明显的东西,或者就是这样?

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...in loop (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来自MDN 上的Object.values()

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来自MDN 上的Array.prototype.reduce()

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).请注意,此代码使用了一些旧版浏览器(如 IE)不支持的一些 ECMAScript 功能。 You might need to use Babel to compile your code.你可能需要使用Babel来编译你的代码。

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 );


For fun's sake here is another implementation using Object.keys() and Array.reduce() (browser support should not be a big issue anymore): 为了好玩,这里是另一个使用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)}`);

But this seems to be way slower: jsperf.com但这似乎要慢得多: jsperf.com

如果您使用的是 lodash,您可以执行类似的操作

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

A regular for loop is pretty concise:常规for循环非常简洁:

var total = 0;

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

You might have to add in object.hasOwnProperty if you modified the prototype.如果您修改了原型,您可能必须添加object.hasOwnProperty

Now you can make use of reduce function and get the sum.现在你可以使用reduce函数并得到总和。

 const object1 = { 'a': 1 , 'b': 2 , 'c':3 } console.log(Object.values(object1).reduce((a, b) => a + b, 0));

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.我们的累加器acc从值 0 开始,正在累加我们对象的所有循环值。 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!它是一个常量函数,因此不会被意外覆盖……为 ES2015 赢得胜利!

Any reason you're not just using a simple for...in loop?您不只是使用简单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/

 let prices = { "apple": 100, "banana": 300, "orange": 250 }; let sum = 0; for (let price of Object.values(prices)) { sum += price; } alert(sum)

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.它是递归的,非 ES6,它应该可以在大多数半现代浏览器中工作。 You use it like this:你像这样使用它:

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

Parameter breakdown:参数分解:

obj = either an object or an array obj = 对象或数组
property = the property within the nested objects/arrays you wish to perform the aggregate method on property = 您希望对其执行聚合方法的嵌套对象/数组中的属性
aggregate = the aggregate method (sum, min, max, or count) aggregate = 聚合方法(sum、min、max 或 count)
shallow = can either be set to true/false or a numeric value shallow = 可以设置为 true/false 或数值
depth = should be left null or undefined (it is used to track the subsequent recursive callbacks) depth = 应为空或未定义(用于跟踪后续的递归回调)

Shallow can be used to enhance performance if you know that you will not need to search deeply nested data.如果您知道不需要搜索深度嵌套的数据,则可以使用 Shallow 来提高性能。 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 属性,因为您要聚合的值没有嵌套那么深,您可以将 shallow 设置为 true。

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

I came across this solution from @jbabey while trying to solve a similar problem.在尝试解决类似问题时,我从@jbabey 遇到了这个解决方案。 With a little modification, I got it right.稍加修改,我就做对了。 In my case, the object keys are numbers (489) and strings ("489").在我的例子中,对象键是数字(489)和字符串(“489”)。 Hence to solve this, each key is parse.因此,为了解决这个问题,每个键都被解析。 The following code works:以下代码有效:

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);

A ramda one liner:一个ramda one 班轮:

import {
 compose, 
 sum,
 values,
} from 'ramda'

export const sumValues = compose(sum, values);

Use: const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });使用: const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });

We can iterate object using in keyword and can perform any arithmetic operation.我们可以使用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);

Sum the object key value by parse Integer.通过解析 Integer 对对象键值求和。 Converting string format to integer and summing the values将字符串格式转换为整数并对值求和

 var obj = { pay: 22 }; obj.pay; console.log(obj.pay); var x = parseInt(obj.pay); console.log(x + 20);

A simple solution would be to use the for..in loop to find the sum.一个简单的解决方案是使用 for..in 循环来查找总和。

function findSum(obj){
  let sum = 0;
  for(property in obj){
    sum += obj[property];
  }
  return sum;
}


var sample = { a: 1 , b: 2 , c:3 };
console.log(findSum(sample));

function myFunction(a) { return Object.values(a).reduce((sum, cur) => sum + cur, 0); }

function totalAmountAdjectives(obj) {
    let sum = 0;
    for(let el in obj) {
            sum += el.length;
    }
    return sum;
}
console.log(totalAmountAdjectives({ a: "apple" }))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM