Лучший способ суммировать значение свойства в массиве
У меня есть что-то вроде этого:
$scope.traveler = [
{ description: 'Senior', Amount: 50},
{ description: 'Senior', Amount: 50},
{ description: 'Adult', Amount: 75},
{ description: 'Child', Amount: 35},
{ description: 'Infant', Amount: 25 },
];
Теперь, чтобы получить общее количество этого массива, я делаю что-то вроде этого:
$scope.totalAmount = function(){
var total = 0;
for (var i = 0; i < $scope.traveler.length; i++) {
total = total + $scope.traveler[i].Amount;
}
return total;
}
Это легко, когда есть только один массив, но у меня есть другие массивы с другим именем свойства, которые я хотел бы суммировать.
Я был бы счастлив, если бы я мог сделать что-то вроде этого:
$scope.traveler.Sum({ Amount });
Но я не знаю, как пройти через это так, чтобы я мог использовать его в будущем, например так:
$scope.someArray.Sum({ someProperty });
Ответ
Я решил использовать предложение @gruff-bunny, чтобы избежать прототипирования нативного объекта (Array)
Я только что сделал небольшую модификацию его ответа, проверяя массив и значение sum не равны null, это моя последняя реализация:
$scope.sum = function (items, prop) {
if (items == null) {
return 0;
}
return items.reduce(function (a, b) {
return b[prop] == null ? a : a + b[prop];
}, 0);
};
Ответы
Ответ 1
Обновленный ответ
Из-за всех недостатков добавления функции в прототип Array я обновляю этот ответ, чтобы предоставить альтернативу, которая поддерживает синтаксис, аналогичный синтаксису, первоначально запрошенному в вопросе.
class TravellerCollection extends Array {
sum(key) {
return this.reduce((a, b) => a + (b[key] || 0), 0);
}
}
const traveler = new TravellerCollection(...[
{ description: 'Senior', Amount: 50},
{ description: 'Senior', Amount: 50},
{ description: 'Adult', Amount: 75},
{ description: 'Child', Amount: 35},
{ description: 'Infant', Amount: 25 },
]);
console.log(traveler.sum('Amount')); //~> 235
Оригинальный ответ
Поскольку это массив, вы можете добавить функцию в прототип Array.
traveler = [
{ description: 'Senior', Amount: 50},
{ description: 'Senior', Amount: 50},
{ description: 'Adult', Amount: 75},
{ description: 'Child', Amount: 35},
{ description: 'Infant', Amount: 25 },
];
Array.prototype.sum = function (prop) {
var total = 0
for ( var i = 0, _len = this.length; i < _len; i++ ) {
total += this[i][prop]
}
return total
}
console.log(traveler.sum("Amount"))
Скрипка: http://jsfiddle.net/9BAmj/
Ответ 2
Я знаю, что этот вопрос имеет принятый ответ, но я подумал, что воспользуюсь альтернативой, которая использует array.reduce, видя, что суммирование массива - это канонический пример для сокращения:
$scope.sum = function(items, prop){
return items.reduce( function(a, b){
return a + b[prop];
}, 0);
};
$scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');
Fiddle
Ответ 3
Еще один пример: для этого были созданы native
функции JavaScript Map
и Reduce
(Map и Reduce - это мощные во многих языках языки).
var traveler = [{description: 'Senior', Amount: 50},
{description: 'Senior', Amount: 50},
{description: 'Adult', Amount: 75},
{description: 'Child', Amount: 35},
{description: 'Infant', Amount: 25}];
function amount(item){
return item.Amount;
}
function sum(prev, next){
return prev + next;
}
traveler.map(amount).reduce(sum);
// => 235;
// or use arrow functions
traveler.map(item => item.Amount).reduce((prev, next) => prev + next);
Примечание: создавая отдельные меньшие функции, мы получаем возможность использовать их снова.
// Example of reuse.
// Get only Amounts greater than 0;
// Also, while using Javascript, stick with camelCase.
// If you do decide to go against the standards,
// then maintain your decision with all keys as in...
// { description: 'Senior', Amount: 50 }
// would be
// { Description: 'Senior', Amount: 50 };
var travelers = [{description: 'Senior', amount: 50},
{description: 'Senior', amount: 50},
{description: 'Adult', amount: 75},
{description: 'Child', amount: 35},
{description: 'Infant', amount: 0 }];
// Directly above Travelers array I changed "Amount" to "amount" to match standards.
function amount(item){
return item.amount;
}
travelers.filter(amount);
// => [{description: 'Senior', amount: 50},
// {description: 'Senior', amount: 50},
// {description: 'Adult', amount: 75},
// {description: 'Child', amount: 35}];
// Does not include "Infant" as 0 is falsey.
Ответ 4
Я всегда избегаю изменения метода-прототипа и добавления библиотеки, так что это мое решение:
Достаточно использовать метод-прототип Reduce Array
// + operator for casting to Number
items.reduce((a, b) => +a + +b.price, 0);
Ответ 5
Я думал, что заброшу два цента на это: это одна из тех операций, которые всегда должны быть чисто функциональными, а не полагаться на какие-либо внешние переменные. Несколько уже дали хороший ответ, использование reduce
- это путь сюда.
Поскольку большинство из нас уже может позволить себе использовать синтаксис ES2015, здесь мое предложение:
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Мы делаем его неизменной функцией, пока мы на ней. Что здесь делает reduce
, так это просто:
Начните со значения 0
для аккумулятора и добавьте к нему значение текущего элемента с петлей.
Yay для функционального программирования и ES2015!:)
Ответ 6
Вы можете сделать следующее:
$scope.traveler.map(o=>o.Amount).reduce((a,c)=>a+c);
Ответ 7
Альтернатива для улучшения читаемости и использования Map
и Reduce
:
const traveler = [
{ description: 'Senior', amount: 50 },
{ description: 'Senior', amount: 50 },
{ description: 'Adult', amount: 75 },
{ description: 'Child', amount: 35 },
{ description: 'Infant', amount: 25 },
];
const sum = traveler
.map(item => item.amount)
.reduce((prev, curr) => prev + curr, 0);
Повторно используемая функция:
const calculateSum = (obj, field) => obj
.map(items => items.attributes[field])
.reduce((prev, curr) => prev + curr, 0);
Ответ 8
Я не уверен, что это было упомянуто еще. Но для этого есть функция lodash. Фрагмент ниже, где значение - это ваш атрибут, а сумма - это "значение".
_.sumBy(objects, 'value');
_.sumBy(objects, function(o) { return o.value; });
Оба будут работать.
Ответ 9
также можно использовать Array.prototype.forEach()
let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;
Ответ 10
Вот однострочник, использующий функции стрелок ES6.
const sumPropertyValue = (items, prop) => items.reduce((a, b) => a + b[prop], 0);
// usage:
const cart_items = [ {quantity: 3}, {quantity: 4}, {quantity: 2} ];
const cart_total = sumPropertyValue(cart_items, 'quantity');
Ответ 11
Как суммировать массив объектов с помощью Javascript
const traveler = [
{ description: 'Senior', Amount: 50},
{ description: 'Senior', Amount: 50},
{ description: 'Adult', Amount: 75},
{ description: 'Child', Amount: 35},
{ description: 'Infant', Amount: 25 }
];
const traveler = [
{ description: 'Senior', Amount: 50},
{ description: 'Senior', Amount: 50},
{ description: 'Adult', Amount: 75},
{ description: 'Child', Amount: 35},
{ description: 'Infant', Amount: 25 },
];
function sum(arrayData, key){
return arrayData.reduce((a,b) => {
return {Amount : a.Amount + b.Amount}
})
}
console.log(sum(traveler))
Ответ 12
Я уже использовал jquery. Но я думаю, что это достаточно интуитивно понятно, чтобы просто иметь:
var total_amount = 0;
$.each(traveler, function( i, v ) { total_amount += v.Amount ; });
По сути, это просто краткая версия ответа @akhouri.
Ответ 13
Вот решение, которое я считаю более гибким:
function sumOfArrayWithParameter (array, parameter) {
let sum = null;
if (array && array.length > 0 && typeof parameter === 'string') {
sum = 0;
for (let e of array) if (e && e.hasOwnProperty(parameter)) sum += e[parameter];
}
return sum;
}
Чтобы получить сумму, просто используйте ее следующим образом:
let sum = sumOfArrayWithParameter(someArray, 'someProperty');