-3

I already searched for a tutorial in Google but couldn't find what I needed. I have an array like this:

[
 {Username:'user1', Balance:'123'}, 
 {Username:'user2', Balance:'213'}, 
 {Username:'user1', Balance:'424'}
]

How to merge Balance when the Username is the same, for example merge Balance Username:'user1'

gyre
  • 16,369
  • 3
  • 37
  • 47
DeVoresyah
  • 86
  • 1
  • 9

3 Answers3

1

You can use a combination of higher-level built-in functions like Object.keys, Array#reduce, and Array#map to conditionally combine array entries when certain properties match.

var array = [{
  Username: 'user1',
  Balance: '123'
}, {
  Username: 'user2',
  Balance: '213'
}, {
  Username: 'user1',
  Balance: '424'
}]

var map = array.reduce(function (map, e) {
  map[e.Username] = +e.Balance + (map[e.Username] || 0) 
  return map
}, {})

var result = Object.keys(map).map(function (k) {
  return { Username: k, Balance: map[k] }
})

console.log(result)

Edit: OP requested that the answer be flexible enough to handle more than one property. I will leave my original snippet up as well, as in the end I think that one was more elegant.

var array = [{
  Username: 'user1',
  Balance: '123',
  Another: '222'
}, {
  Username: 'user2',
  Balance: '213',
  Another: '111'
}, {
  Username: 'user1',
  Balance: '424',
  Another: '121'
}]

// Add elements to this array if you need to handle more properties
var properties = ['Balance', 'Another']

var map = array.reduce(function (map, e) {
  map[e.Username] = properties.map(function (property, i) {
    return +e[property] + ((map[e.Username] || [])[i] || 0)
  })
  return map
}, {})

var result = Object.keys(map).map(function (k) {
  return map[k].reduce(function (object, e, i) {
    object[properties[i]] = e
    return object
  }, { Username: k })
})

console.log(result)
gyre
  • 16,369
  • 3
  • 37
  • 47
  • you are using a bitwise OR `map[e.Username] |= 0`, which advantage has this over a logical OR? – Nina Scholz Mar 05 '17 at 07:53
  • I was trying to avoid writing `map[e.Username]` one more time, but I think I see a way to combine the two assignments now. Give me a moment to edit :) – gyre Mar 05 '17 at 07:55
  • @gyre how for multiple sum? example: `var array = [{ Username: 'user1', Balance: '123', Another: '222' }, { Username: 'user2', Balance: '213', Another: '111' }, { Username: 'user1', Balance: '424', Another: '121' }]` – DeVoresyah Mar 05 '17 at 09:16
  • I believe that is the exact array I used in my example code. Did you have a question about something related to it? – gyre Mar 05 '17 at 09:19
  • @gyre it works for sum `balance` and how if another number to sum, whats code i must add into your code example – DeVoresyah Mar 05 '17 at 09:27
  • @DeVoresyah I added a second snippet for you, go ahead and check it out – gyre Mar 05 '17 at 10:04
  • @gyre oh my god, its really awesome bro.. thanks, really thanks – DeVoresyah Mar 05 '17 at 10:13
  • @gyre sir i found a bug again, can you fix it or i must create ask question again in Stackoverflow. – DeVoresyah Mar 06 '17 at 10:22
  • I cannot fix it at the moment, sorry, but if you let me know what is wrong here I can take a look at it later today. – gyre Mar 06 '17 at 10:25
1

You could use a single loop with a hash table for the reference to the objects with the same Username.

var data = [{ Username: 'user1', Balance: '123' }, { Username: 'user2', Balance: '213' }, { Username: 'user1', Balance: '424' }],
    grouped = [];
    
data.forEach(function (hash) {
    return function (o) {
        if (!hash[o.Username]) {
            hash[o.Username] = { Username: o.Username, Balance: 0 };
            grouped.push(hash[o.Username]);
        }
        hash[o.Username].Balance += +o.Balance;
    };
}(Object.create(null)));

console.log(grouped);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Here's one more solution, which I find a smidge less magicky than gyre's (but I'm also very interested by his.)

function mergeBalances(x) {
    var users = [];
    users = x.filter(function(entry) {
                        if(users[entry.Username]) { return false;}
                        users[entry.Username] = entry.Username;
                        return true;
                     })
             .map(function(e) { return e.Username; } );

    balances = {};
    for(var i=0; i < users.length; i++) {
            balances[i] = { Username:users[i]};
            balances[i].Balance = x.filter(function(e) { return e.Username==users[i]; })
                                   .reduce(function(total, e) { return total + eval(e.Balance);}, 0);
    }

    return balances;
}

// just call the function on your array
x = [ {Username:'user1', Balance:'123'}, {Username:'user2', Balance:'213'}, {Username:'user1', Balance:'424'} ]
console.log(mergeBalances(x));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
Will Jobs
  • 362
  • 1
  • 11