javascript - Mejor manera de sumar el valor de una propiedad en un arreglo
Tengo algo así:
$scope.traveler = [
{ description: 'Senior', Amount: 50},
{ description: 'Senior', Amount: 50},
{ description: 'Adult', Amount: 75},
{ description: 'Child', Amount: 35},
{ description: 'Infant', Amount: 25 },
];
Ahora, para tener un monto total de este arreglo, estoy haciendo algo así:
$scope.totalAmount = function(){
var total = 0;
for (var i = 0; i < $scope.traveler.length; i++) {
total = total + $scope.traveler[i].Amount;
}
return total;
}
Es fácil cuando hay solo un arreglo, pero tengo otros arreglos con un nombre de propiedad diferente que me gustaría sumar.
Sería más feliz si pudiera hacer algo como esto:
$scope.traveler.Sum({ Amount });
Pero no sé cómo pasar por esto de una manera que pueda reutilizarlo en el futuro así:
$scope.someArray.Sum({ someProperty });
Respuesta #1
Sé que esta pregunta tiene una respuesta aceptada, pero pensé en aportar una alternativa que use array.reduce, dado que sumar un arreglo es el ejemplo canónico para reduce:
$scope.sum = function(items, prop){
return items.reduce( function(a, b){
return a + b[prop];
}, 0);
};
$scope.travelerTotal = $scope.sum($scope.traveler, 'Amount');
Violín
Respuesta #2
Usa reduce con destructuración para sumar Amount:
const traveler = [
{ description: 'Senior', Amount: 50 },
{ description: 'Senior', Amount: 50 },
{ description: 'Adult', Amount: 75 },
{ description: 'Child', Amount: 35 },
{ description: 'Infant', Amount: 25 },
];
console.log(traveler.reduce((n, {Amount}) => n + Amount, 0));Respuesta #3
Solo otra versión, esto es para lo que fueron creadas las funciones
nativede JavaScriptMapyReduce(Map y Reduce son potencias en muchos lenguajes).
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);
Nota: al crear funciones más pequeñas por separado obtenemos la capacidad de usarlas de nuevo.
// 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.
Respuesta #4
Respuesta Actualizada
Debido a todos los inconvenientes de añadir una función al prototipo de Array, estoy actualizando esta respuesta para proporcionar una alternativa que mantenga la sintaxis similar a la sintaxis solicitada originalmente en la pregunta.
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')); //~> 235Respuesta Original
Dado que es un arreglo, podrías agregar una función al prototipo de 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"))Respuesta #5
Siempre evito cambiar el método del prototipo y agregar bibliotecas, así que esta es mi solución:
Usar el método prototipo reduce de Array es suficiente
// + operator for casting to Number
items.reduce((a, b) => +a + +b.price, 0);
Respuesta #6
Alternativa para una mejor legibilidad y utilizando Map y 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);
Función reutilizable:
const calculateSum = (obj, field) => obj
.map(items => items.attributes[field])
.reduce((prev, curr) => prev + curr, 0);
Respuesta #7
Está funcionando para mí en TypeScript y JavaScript:
let lst = [
{ description:'Senior', price: 10},
{ description:'Adult', price: 20},
{ description:'Child', price: 30}
];
let sum = lst.map(o => o.price).reduce((a, c) => { return a + c });
console.log(sum);Espero que sea útil.
Respuesta #8
Puedes hacer lo siguiente:
$scope.traveler.map(o=>o.Amount).reduce((a,c)=>a+c);
Respuesta #9
Pensé en dar mi opinión sobre esto: esta es una de esas operaciones que siempre debería ser puramente funcional, sin depender de ninguna variable externa. Algunos ya dieron una buena respuesta, usar reduce es el camino a seguir aquí.
Dado que la mayoría de nosotros ya podemos permitirnos usar la sintaxis de ES2015, aquí está mi propuesta:
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Estamos convirtiéndolo en una función inmutable mientras lo hacemos. Lo que reduce está haciendo aquí es simplemente esto: comenzar con un valor de 0 para el acumulador, y sumarle el valor del elemento actual del bucle.
¡Hurra por la programación funcional y ES2015! :)
Respuesta #10
No estoy seguro de que esto se haya mencionado todavía. Pero hay una función de lodash para eso. El fragmento abajo donde 'value' es tu atributo a sumar es 'value'.
_.sumBy(objects, 'value');
_.sumBy(objects, function(o) { return o.value; });
Ambos funcionarán.
