1
var players = [{id: 17, amount: 126},
{id: 17, amount: 45},
{id: 12, amount: 44},
{id: 12, amount: 23}];

How would i turn the above array into a new array adding the amount for each id.

var newArray=[{id:17.amount:171},{id:12,amount:67}];
4
  • @AdamAzad You can not see how 126+45=171? Commented Oct 28, 2016 at 13:15
  • check out underscorejs Commented Oct 28, 2016 at 13:15
  • I would use reduce() to make an object and than I would loop over that to make your need array. Commented Oct 28, 2016 at 13:16
  • @AdamAzad The sum is group by id, id 17 is 126+45. Commented Oct 28, 2016 at 13:19

3 Answers 3

4

You could group the same id with a hash table and add the amount, where necessary.

var players = [{ id: 17, amount: 126 }, { id: 17, amount: 45 }, { id: 12, amount: 44 }, { id: 12, amount: 23 }],
    grouped = players.reduce(function (hash) {
        return function (r, a) {
            (hash[a.id] = hash[a.id] || r[r.push({ id: a.id, amount: 0 }) - 1]).amount += a.amount;
            return r;
        };
    }(Object.create(null)), []);

console.log(grouped);

Basically this line

(hash[a.id] = hash[a.id] || r[r.push({ id: a.id, amount: 0 }) - 1]).amount += a.amount;

checks if hash[a.id] exists and if not, then this part

r[r.push({ id: a.id, amount: 0 }) - 1]

is perfomed, which contains of two parts, a part to access the result set and inside it pushes a new objetc set to the result set. While push returns the new length of the array, it need to decrease the index to get the last inserted element.

r[                                - 1]
  r.push({ id: a.id, amount: 0 })

After that, take the property amount and increase by the amount of the actual element.

Sign up to request clarification or add additional context in comments.

4 Comments

Why are you using Object.create(null) instead of {}?
to prevent some id like 'toString' to break the hash table.
The code seems to work fine with {}. You might also want to explain what's going on in here. Even with years of JS experience, this isn't exactly easy to read, not to mention understand.
in this case where only numbers are keys, yes.
0

You could also change the output format a little, to make it easier to search:

var players = [{ id: 17, amount: 126 }, { id: 17, amount: 45 }, { id: 12, amount: 44 }, { id: 12, amount: 23 }],
    result = {};

for(var i = 0; i < players.length; i++){
  result[players[i].id] = 
      (result[players[i].id] || 0) + // The existing amount, or 0 for a new `id`
       players[i].amount;           // Add the current amount
}

console.log(result);
console.log('Amount for 17: ' + result[17]);

This way, you don't have to filter the result on it's id value, to get the amount.

Comments

0

You could push element in a a new array if id is new or just add amount to the previous if it already exists :

var players = [{ id: 17, amount: 126 }, { id: 12, amount: 103 }, { id: 17, amount: 45 }, { id: 12, amount: 44 }, { id: 12, amount: 23 }];
var results = [];
results.push(players.sort((a,b) => a.id-b.id)[0]);
var shift = 0;
players.forEach((item, index, arr) => {
   if (index < arr.length - 1){
     if (item.id === arr[index+1].id) {
       results[index + shift].amount += arr[index+1].amount;
       shift--;
     }
     else results.push(players[index+1]);
   }
});
console.log(results); // [ { id: 12, amount: 170 }, { id: 17, amount: 171 } ]

2 Comments

This code doesn't work if the players aren't sorted by id.
@Cerbrus, I've just fixed the bug above. I also changed the set of tests to prove my sort() is efficient to produce expected result.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.