Count sum of values in JSON array

Viewed 1210

Having an array like this:

const data = [
    {
        "name": "Dave",
        "coins": 14,
        "weapons": 2,
        "otherItems": 3,
        "color": "red"
    },
    {
        "name": "Vanessa",
        "coins": 18,
        "weapons": 1,
        "otherItems": 5,
        "color": "blue"
    },
    {
        "name": "Sharon",
        "coins": 9,
        "weapons": 5,
        "otherItems": 1,
        "color": "pink"
    },
    {
        "name": "Walter",
        "coins": 9,
        "weapons": 2,
        "otherItems": 4,
        "color": "white"
    }
]

How to count sum of coins, weapons and otherItems using ES6 features? (I'm not attached to this: any simple method would be good.)

data.reduce((first, last) => first + last) generates a chain of [object Object][object Object]s...

4 Answers

You have to process every field separately (note that when you don't specify second parameter for reduce it will take first array object as seed and start processing from the second one):

const data = [
    {
        "name": "Dave",
        "coins": 14,
        "weapons": 2,
        "otherItems": 3,
        "color": "red"
    },
    {
        "name": "Vanessa",
        "coins": 18,
        "weapons": 1,
        "otherItems": 5,
        "color": "blue"
    },
    {
        "name": "Sharon",
        "coins": 9,
        "weapons": 5,
        "otherItems": 1,
        "color": "pink"
    },
    {
        "name": "Walter",
        "coins": 9,
        "weapons": 2,
        "otherItems": 4,
        "color": "white"
    }
]

let result = data.reduce((a,c)=> ({ 
     coins: a.coins + c.coins, 
     weapons: a.weapons + c.weapons, 
     otherItems: a.otherItems + c.otherItems })
)

console.log(result);

You could take an array of wanted keys for the sums and create an object for the sums and add the wanted values.

const
    data = [{ name: "Dave", coins: 14, weapons: 2, otherItems: 3, color: "red" }, { name: "Vanessa", coins: 18, weapons: 1, otherItems: 5, color: "blue" }, { name: "Sharon", coins: 9, weapons: 5, otherItems: 1, color: "pink" }, { name: "Walter", coins: 9, weapons: 2, otherItems: 4, color: "white" }],
    keys = ['coins', 'weapons', 'otherItems'],
    sums = data.reduce(
        (r, o) => (keys.forEach(k => r[k] += o[k]), r), 
        Object.fromEntries(keys.map(k => [k, 0]))
    );

console.log(sums);

You can use Array.prototype.reduce for this.

To make it a little bit more flexible and dynamic, make a Set of keys you want to get a count of.

Then go through each key in the Set and if that key is in the obj, sum it up in an accumulator object in the reduce callback:

const data = [{"name":"Dave","coins":14,"weapons":2,"otherItems":3,"color":"red"},{"name":"Vanessa","coins":18,"weapons":1,"otherItems":5,"color":"blue"},{"name":"Sharon","coins":9,"weapons":5,"otherItems":1,"color":"pink"},{"name":"Walter","coins":9,"weapons":2,"otherItems":4,"color":"white"}]

//Keys to count
const keys = new Set(["coins", "weapons", "otherItems"]);

const count = data.reduce((acc, obj) => {
  const objKeys = keys.forEach(key => {
    if (obj.hasOwnProperty(key)) {
      acc[key] = (acc[key] || 0) + obj[key];
    }
  });
  return acc;
}, {});
console.log(count);

Your idea is right, you need to use reduce method. The problem is that you're summing two objects, not their properties. All you need to do is change the code to the following (to sum the coins):

data.reduce((first, last) => first.coins + last.coins, 0)

And following for weapons:

data.reduce((first, last) => first.weapons + last.weapons, 0)
Related