Jonathan Vanasco
Jonathan Vanasco

Reputation: 15690

How to sum the values of a JavaScript object?

I'd like to sum the values of an object.

I'm used to python where it would just be:

sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed =  sum(sample.itervalues())     

The following code works, but it's a lot of code:

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)

Am i missing anything obvious, or is this just the way it is?

Upvotes: 149

Views: 305185

Answers (17)

Cherma Ramalho
Cherma Ramalho

Reputation: 395

A simple and clean solution for typescrip:

const sample = { a: 1, b: 2, c: 3 };  
const totalSample = Object.values(sample).reduce(
  (total: number, currentElement: number) => total + currentElement
);
console.log(totalSample);

Good luck!

Upvotes: -4

Michał Perłakowski
Michał Perłakowski

Reputation: 92709

It can be as simple as that:

const sumValues = obj => Object.values(obj).reduce((a, b) => a + b, 0);

Quoting MDN:

The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).

from Object.values() on MDN

The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.

from Array.prototype.reduce() on MDN

You can use this function like that:

sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5

Note that this code uses some ECMAScript features which are not supported by some older browsers (like IE). You might need to use Babel to compile your code.

Upvotes: 185

Dhrupad Patel
Dhrupad Patel

Reputation: 61

function myFunction(a) { return Object.values(a).reduce((sum, cur) => sum + cur, 0); }

Upvotes: 0

Alex Irabor
Alex Irabor

Reputation: 401

A simple solution would be to use the for..in loop to find the sum.

function findSum(obj){
  let sum = 0;
  for(property in obj){
    sum += obj[property];
  }
  return sum;
}


var sample = { a: 1 , b: 2 , c:3 };
console.log(findSum(sample));

Upvotes: 0

Surya R Praveen
Surya R Praveen

Reputation: 3745

Sum the object key value by parse Integer. Converting string format to integer and summing the values

var obj = {
  pay: 22
};
obj.pay;
console.log(obj.pay);
var x = parseInt(obj.pay);
console.log(x + 20);

Upvotes: -1

sachinsuthariya
sachinsuthariya

Reputation: 267

We can iterate object using in keyword and can perform any arithmetic operation.

// input
const sample = {
    'a': 1,
    'b': 2,
    'c': 3
};

// var
let sum = 0;

// object iteration
for (key in sample) {
    //sum
    sum += (+sample[key]);
}
// result
console.log("sum:=>", sum);

Upvotes: 0

Sudam Dissanayake
Sudam Dissanayake

Reputation: 146

let prices = {
  "apple": 100,
  "banana": 300,
  "orange": 250
};

let sum = 0;
for (let price of Object.values(prices)) {
  sum += price;
}

alert(sum)

Upvotes: 3

Ismael Soschinski
Ismael Soschinski

Reputation: 475

Use 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

Upvotes: 1

Krishnadas PC
Krishnadas PC

Reputation: 6539

Now you can make use of reduce function and get the sum.

const object1 = { 'a': 1 , 'b': 2 , 'c':3 }

console.log(Object.values(object1).reduce((a, b) => a + b, 0));

Upvotes: 29

Sirko
Sirko

Reputation: 74106

You could put it all in one function:

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


For fun's sake here is another implementation using Object.keys() and Array.reduce() (browser support should not be a big issue anymore):

function sum(obj) {
  return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
}
let sample = { a: 1 , b: 2 , c:3 };

console.log(`sum:${sum(sample)}`);

But this seems to be way slower: jsperf.com

Upvotes: 98

Damian Green
Damian Green

Reputation: 7535

A ramda one liner:

import {
 compose, 
 sum,
 values,
} from 'ramda'

export const sumValues = compose(sum, values);

Use: const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });

Upvotes: 0

user5487386
user5487386

Reputation:

I am a bit tardy to the party, however, if you require a more robust and flexible solution then here is my contribution. If you want to sum only a specific property in a nested object/array combo, as well as perform other aggregate methods, then here is a little function I have been using on a React project:

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

It is recursive, non ES6, and it should work in most semi-modern browsers. You use it like this:

const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');

Parameter breakdown:

obj = either an object or an array
property = the property within the nested objects/arrays you wish to perform the aggregate method on
aggregate = the aggregate method (sum, min, max, or count)
shallow = can either be set to true/false or a numeric value
depth = should be left null or undefined (it is used to track the subsequent recursive callbacks)

Shallow can be used to enhance performance if you know that you will not need to search deeply nested data. For instance if you had the following array:

[
    {
        id: 1,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 2,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    {
        id: 3,
        otherData: { ... },
        valueToBeTotaled: ?
    },
    ...
]

If you wanted to avoid looping through the otherData property since the value you are going to be aggregating is not nested that deeply, you could set shallow to true.

Upvotes: 1

Olu Adabonyan
Olu Adabonyan

Reputation: 93

I came across this solution from @jbabey while trying to solve a similar problem. With a little modification, I got it right. In my case, the object keys are numbers (489) and strings ("489"). Hence to solve this, each key is parse. The following code works:

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

Upvotes: 0

Ricardo Magalh&#227;es
Ricardo Magalh&#227;es

Reputation: 1871

Honestly, given our "modern times" I'd go with a functional programming approach whenever possible, like so:

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

Our accumulator acc, starting with a value of 0, is accumulating all looped values of our object. This has the added benefit of not depending on any internal or external variables; it's a constant function so it won't be accidentally overwritten... win for ES2015!

Upvotes: 15

Leon
Leon

Reputation: 6089

If you're using lodash you can do something like

_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 })) 

Upvotes: 30

jbabey
jbabey

Reputation: 46657

Any reason you're not just using a simple for...in loop?

var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;

for (var key in sample) {
    summed += sample[key];
};

http://jsfiddle.net/vZhXs/

Upvotes: 13

Blender
Blender

Reputation: 298562

A regular for loop is pretty concise:

var total = 0;

for (var property in object) {
    total += object[property];
}

You might have to add in object.hasOwnProperty if you modified the prototype.

Upvotes: 24

Related Questions