Better way to sum a property value in an array

JavascriptArraysPrototype Programming

Javascript Problem Overview


I have something like this:

$scope.traveler = [
            {  description: 'Senior', Amount: 50},
            {  description: 'Senior', Amount: 50},
            {  description: 'Adult', Amount: 75},
            {  description: 'Child', Amount: 35},
            {  description: 'Infant', Amount: 25 },
];

Now to have a total Amount of this array I'm doing something like this:

$scope.totalAmount = function(){
       var total = 0;
       for (var i = 0; i < $scope.traveler.length; i++) {
              total = total + $scope.traveler[i].Amount;
            }
       return total;
}

It's easy when is only one array, but I have others arrays with a different property name that I would like to sum.

I would be happier If I could do something like this:

$scope.traveler.Sum({ Amount });

But I don't know how to go through this in a way that I could reuse it in the future like this:

$scope.someArray.Sum({ someProperty });

Javascript Solutions


Solution 1 - Javascript

I know that this question has an accepted answer but I thought I'd chip in with an alternative which uses array.reduce, seeing that summing an array is the canonical example for 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

Solution 2 - Javascript

> Just another take, this is what native JavaScript functions Map and Reduce were built for (Map and Reduce are powerhouses in many languages).

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);

> Note: by making separate smaller functions we get the ability to use them again.

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

Solution 3 - Javascript

Updated Answer

Due to all the downsides of adding a function to the Array prototype, I am updating this answer to provide an alternative that keeps the syntax similar to the syntax originally requested in the question.

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

Original Answer

Since it is an array you could add a function to the Array prototype.

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"))

The Fiddle: http://jsfiddle.net/9BAmj/

Solution 4 - Javascript

I always avoid changing prototype method and adding library so this is my solution:

Using reduce Array prototype method is sufficient

// + operator for casting to Number
items.reduce((a, b) => +a + +b.price, 0);

Solution 5 - Javascript

Use reduce with destructuring to sum 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))

Solution 6 - Javascript

Alternative for improved readability and using Map and 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);

Re-useable function:

const calculateSum = (obj, field) => obj
  .map(items => items.attributes[field])
  .reduce((prev, curr) => prev + curr, 0);

Solution 7 - Javascript

I thought I'd drop my two cents on this: this is one of those operations that should always be purely functional, not relying on any external variables. A few already gave a good answer, using reduce is the way to go here.

Since most of us can already afford to use ES2015 syntax, here's my proposition:

const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);

We're making it an immutable function while we're at it. What reduce is doing here is simply this: Start with a value of 0 for the accumulator, and add the value of the current looped item to it.

Yay for functional programming and ES2015! :)

Solution 8 - Javascript

You can do the following:

$scope.traveler.map(o=>o.Amount).reduce((a,c)=>a+c);

Solution 9 - Javascript

It's working for me in TypeScript and 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);

I hope is useful.

Solution 10 - Javascript

I'm not sure this has been mentioned yet. But there is a lodash function for that. Snippet below where value is your attribute to sum is 'value'.

_.sumBy(objects, 'value');
_.sumBy(objects, function(o) { return o.value; });

Both will work.

Solution 11 - Javascript

From array of objects

function getSum(array, column)
  let values = array.map((item) => parseInt(item[column]) || 0)
  return values.reduce((a, b) => a + b)
}

foo = [  { a: 1, b: "" },  { a: null, b: 2 },  { a: 1, b: 2 },  { a: 1, b: 2 },]

getSum(foo, a) == 3
getSum(foo, b) == 6

Solution 12 - Javascript

can also use [Array.prototype.forEach()][1]

let totalAmount = 0;
$scope.traveler.forEach( data => totalAmount = totalAmount + data.Amount);
return totalAmount;

[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach "Array.prototype.forEach()"

Solution 13 - Javascript

Here is a one-liner using ES6 arrow functions.

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');

Solution 14 - Javascript

How to sum array of object using 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))

`

Solution 15 - Javascript

Here's a solution I find more flexible:

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;
}

To get the sum, simply use it like that:

let sum = sumOfArrayWithParameter(someArray, 'someProperty');

Solution 16 - Javascript

After going through these answers I think that actually a for (or forEach or for of with await) loop is much more readable that than reduce or even map and reduce. Think of:

  1. coming back to this code after 6 months or maintaining this by someone else. I think your approach of using a loop is good enough.
  2. extending this function in the future, in case you might want to add a currency conversion or similar. Doing this in a one-liner is not a great idea.

var traveler = [
  {Amount: 50,  description: 'Senior'},
  {Amount: 50,  description: 'Senior'},
  {Amount: 75,  description: 'Adult'},
  {Amount: 35,  description: 'Child'},
  {Amount: 25,  description: 'Infant'}
];

var sumFromArray = (propertyName, array) => {
  let sum = 0;
  array.forEach(item => {
    sum += item[propertyName] ?? 0;
  });
  return sum;
};

var sumOfTraveler = sumFromArray('Amount', traveler);
console.log(sumOfTraveler);

Using types your function definition might look like:

const sumFromArray = (propertyName: string, array: Array<{[propertyName: string]: number}>) => { ... };

See here for more details: https://stackoverflow.com/questions/44110641/typescript-a-computed-property-name-in-a-type-literal-must-directly-refer-to-a-b

I have nothing against map, reduce or one-liners, this is just food for thought.

Solution 17 - Javascript

I was already using jquery. But I think its intuitive enough to just have:

var total_amount = 0; 
$.each(traveler, function( i, v ) { total_amount += v.Amount ; });

This is basically just a short-hand version of @akhouri's answer.

Solution 18 - Javascript

i honestly got frustrated while reading all the code that where posted as a solution to this cus i'm a new be and i'n trying to add a functionality to a simple app for practice. The simple way to solve this is

let testArray = [5, 7, 8, 4];

function(){
sum = 0;
for(let i = 0; i < testArray.length; i++){
    sum += testArray[i];
}

// will give you the sum of the array

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnramirezView Question on Stackoverflow
Solution 1 - JavascriptGruff BunnyView Answer on Stackoverflow
Solution 2 - JavascriptSoEzPzView Answer on Stackoverflow
Solution 3 - JavascriptbottensView Answer on Stackoverflow
Solution 4 - JavascriptEric MarcelinoView Answer on Stackoverflow
Solution 5 - JavascriptPatrick LeibView Answer on Stackoverflow
Solution 6 - JavascriptcodingbambyView Answer on Stackoverflow
Solution 7 - JavascriptRicardo MagalhãesView Answer on Stackoverflow
Solution 8 - JavascriptgreenifView Answer on Stackoverflow
Solution 9 - JavascriptAminRostamiView Answer on Stackoverflow
Solution 10 - JavascriptLiam MiddletonView Answer on Stackoverflow
Solution 11 - JavascriptFranzView Answer on Stackoverflow
Solution 12 - JavascriptakhouriView Answer on Stackoverflow
Solution 13 - JavascriptSteve BreeseView Answer on Stackoverflow
Solution 14 - Javascriptkvimalkr55View Answer on Stackoverflow
Solution 15 - JavascriptPhilippe GenoisView Answer on Stackoverflow
Solution 16 - Javascriptlukas_oView Answer on Stackoverflow
Solution 17 - JavascriptSpiRailView Answer on Stackoverflow
Solution 18 - JavascriptHabeeb AwolumateView Answer on Stackoverflow