Как суммировать значения объекта JavaScript?
Я хотел бы суммировать значения объекта.
Я использую 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
Вы можете поместить все это в одну функцию:
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 );
Ответ 2
Это может быть так просто:
const sumValues = obj => Object.values(obj).reduce((a, b) => a + b);
Цитирование MDN:
Метод Object.values()
возвращает массив соответствующих значений свойств Object.values()
объекта в том же порядке, что и for...in
цикла for...in
(разница заключается в том, что цикл for-in перечисляет свойства в цепочке прототипов также).
из Object.values()
в MDN
Метод reduce()
применяет функцию к аккумулятору и каждому значению массива (слева направо), чтобы уменьшить его до одного значения.
из Array.prototype.reduce()
на MDN
Вы можете использовать эту функцию следующим образом:
sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5
Обратите внимание, что в этом коде используются некоторые функции ECMAScript, которые не поддерживаются некоторыми более старыми браузерами (например, IE). Возможно, вам придется использовать Babel для компиляции вашего кода.
Ответ 3
Регулярный цикл for
довольно краток:
var total = 0;
for (var property in object) {
total += object[property];
}
Возможно, вам придется добавить object.hasOwnProperty
, если вы изменили прототип.
Ответ 4
Если вы используете lodash, вы можете сделать что-то вроде
_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 }))
Ответ 5
Любая причина, по которой вы не просто используете простой цикл 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/
Ответ 6
Честно говоря, учитывая наши "современные времена", я по возможности использовал бы функциональный программный подход, например:
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Наш аккумулятор acc
, начиная со значения 0, накапливает все зацикленные значения нашего объекта. Это имеет дополнительное преимущество независимо от каких-либо внутренних или внешних переменных; это постоянная функция, поэтому она не будет случайно перезаписана... выиграть для ES2015!
Ответ 7
Теперь вы можете использовать reduce
функцию и получить сумму.
const object1 = { 'a': 1 , 'b': 2 , 'c':3 }
console.log(Object.values(object1).reduce((a, b) => a + b, 0));
Ответ 8
Я немного опоздал на вечеринку, однако, если вам требуется более надежное и гибкое решение, то вот мой вклад. Если вы хотите суммировать только определенное свойство во вложенном комбайне object/array, а также выполнять другие агрегированные методы, то вот небольшая функция, которую я использовал в проекте 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/false или числовое значение
глубина= должна быть оставлена нулевой или undefined (она используется для отслеживания последующих рекурсивных обратных вызовов)
Неглубокие можно использовать для повышения производительности, если вы знаете, что вам не нужно искать глубоко вложенные данные. Например, если у вас был следующий массив:
[
{
id: 1,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 2,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 3,
otherData: { ... },
valueToBeTotaled: ?
},
...
]
Если вы хотите избежать циклического перехода через свойство otherData, так как значение, которое вы собираетесь агрегировать, не вложено настолько глубоко, что вы можете установить неглубокое значение true.
Ответ 9
Я столкнулся с этим решением от @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);
Ответ 10
Рампа один лайнер:
import {
compose,
sum,
values,
} from 'ramda'
export const sumValues = compose(sum, values);
Использовать: const summed = sumValues({ 'a': 1, 'b': 2, 'c':3 });
Ответ 11
Используйте 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