Búsqueda de sitios web

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 native de JavaScript Map y Reduce (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')); //~> 235

Respuesta 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.

Artículos relacionados