如何对 JavaScript 对象的值求和?
Posted
技术标签:
【中文标题】如何对 JavaScript 对象的值求和?【英文标题】:How to sum the values of a JavaScript object? 【发布时间】:2013-05-03 04:36:52 【问题描述】:我想对一个对象的值求和。
我已经习惯了 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)
我是否遗漏了任何明显的东西,还是就是这样?
【问题讨论】:
【参考方案1】:可以这么简单:
const sumValues = obj => Object.values(obj).reduce((a, b) => a + b);
引用 MDN:
Object.values()
方法返回给定对象自己的可枚举属性值的数组,其顺序与for...in
循环提供的顺序相同(区别在于 for-in 循环也枚举原型链中的属性)。
来自Object.values()
on MDN
reduce()
方法对累加器和数组的每个值(从左到右)应用函数以将其减少为单个值。
来自Array.prototype.reduce()
on MDN
你可以这样使用这个函数:
sumValues(a: 4, b: 6, c: -5, d: 0); // gives 5
请注意,此代码使用了一些旧版浏览器(如 IE)不支持的一些 ECMAScript 功能。您可能需要使用Babel 来编译您的代码。
【讨论】:
这需要你拉出一个 60K 的库 just 以拥有Object.values()
,它将在除 Firefox 之外的每个浏览器上用 for
循环填充。即使没有 polyfill,对我来说,它也比常规的 for
循环慢 4 倍。
@Blender 如果您想使用 任何 的新 ECMAScript 功能并仍支持旧版浏览器,则无论如何都需要使用 Babel。此外,如果有人在 2 年后访问这个问题,现代浏览器可能会在那个时候实现Object.values()
。
接受的答案有一个非常相似的方法,但传递给reduce
的函数似乎更简单一些。您是否故意省略了解析?
@Cerbrus 我假设该对象中的所有值都是数字。
@Blender 看来我是对的——一年半过去了,Object.values()
is supported by all modern browsers。【参考方案2】:
你可以把它全部放在一个函数中:
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
【讨论】:
return sum + parseFloat( obj[key] || 0) 检查 false 或 null /blank 值 很好地突出了解决方案之间的性能差异。虽然Object.keys().reduce
看起来更加优雅,但速度却慢了 60%。
niiiiiiiiceeeeeee【参考方案3】:
如果你使用 lodash,你可以做类似的事情
_.sum(_.values( 'a': 1 , 'b': 2 , 'c':3 ))
【讨论】:
我认为 JS 将值视为字符串。所以答案应该是“123”而不是“6”。如果我错了,请纠正我。【参考方案4】:常规的for
循环非常简洁:
var total = 0;
for (var property in object)
total += object[property];
如果您修改了原型,您可能需要添加 object.hasOwnProperty
。
【讨论】:
【参考方案5】:现在你可以利用reduce
函数得到总和。
const object1 = 'a': 1 , 'b': 2 , 'c':3
console.log(Object.values(object1).reduce((a, b) => a + b, 0));
【讨论】:
【参考方案6】:老实说,鉴于我们的“现代”,我会尽可能采用函数式编程方法,如下所示:
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
我们的累加器acc
,从 0 开始,正在累加我们对象的所有循环值。这具有不依赖于任何内部或外部变量的额外好处;它是一个常量函数,所以它不会被意外覆盖...为 ES2015 赢得胜利!
【讨论】:
【参考方案7】:您不只是使用简单的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/
【讨论】:
【参考方案8】:let prices =
"apple": 100,
"banana": 300,
"orange": 250
;
let sum = 0;
for (let price of Object.values(prices))
sum += price;
alert(sum)
【讨论】:
【参考方案9】:我有点迟到了,但是,如果您需要更强大和灵活的解决方案,那么这是我的贡献。如果您只想对嵌套对象/数组组合中的特定属性求和,以及执行其他聚合方法,那么这是我在 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 = 对象或数组属性 = 您希望对其执行聚合方法的嵌套对象/数组中的属性aggregate = 聚合方法(sum、min、max 或 count)shallow = 可以设置为 true/false 或数值depth = 应为空或未定义(用于跟踪后续的递归回调)
如果您知道不需要搜索深度嵌套的数据,则可以使用 Shallow 来提高性能。例如,如果您有以下数组:
[
id: 1,
otherData: ... ,
valueToBeTotaled: ?
,
id: 2,
otherData: ... ,
valueToBeTotaled: ?
,
id: 3,
otherData: ... ,
valueToBeTotaled: ?
,
...
]
如果您想避免循环遍历 otherData 属性,因为您要聚合的值没有嵌套那么深,您可以将 shallow 设置为 true。
【讨论】:
【参考方案10】:使用 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
【讨论】:
【参考方案11】:我在尝试解决类似问题时从@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);
【讨论】:
【参考方案12】:一个ramda一个班轮:
import
compose,
sum,
values,
from 'ramda'
export const sumValues = compose(sum, values);
使用:
const summed = sumValues( 'a': 1 , 'b': 2 , 'c':3 );
【讨论】:
【参考方案13】:我们可以使用 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);
【讨论】:
【参考方案14】:通过解析Integer对对象键值求和。将字符串格式转换为整数并对值求和
var obj =
pay: 22
;
obj.pay;
console.log(obj.pay);
var x = parseInt(obj.pay);
console.log(x + 20);
【讨论】:
【参考方案15】:一个简单的解决方案是使用 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));
【讨论】:
以上是关于如何对 JavaScript 对象的值求和?的主要内容,如果未能解决你的问题,请参考以下文章
Javascript/jQuery/Datatables 对复选框触发的值求和
javascript es6 多维数组对象相同属性值{key:value}的求和
javascript es6 多维数组对象相同属性值{key:value}的求和