Reputation: 3760
I'm trying to solve this issue:
I have an array like that (I cannot change the way it is structured):
[
[{rivals: ['player1','player2'], winner: "player1"}],
[{rivals: ['player1','player3'], winner: "none"}],
[{rivals: ['player2','player3'], winner: "player3"}],
[{rivals: ['player1','player4'], winner: "none"}]
]
What I'm trying to get is: count every player's points, ie if a player (f.ex player1) wins the player counter is increasing by 3points, if none of rivals win then both counters will be increased by 1point. So at the end I would like to get something like (basing on the example above):
const player1Counter = 5;
const player2Counter = 0;
const player3Counter = 4;
const player4Counter = 1;
Thank you for helping!
Upvotes: 1
Views: 136
Reputation: 31682
You can use Array.reduce()
for that. For each sub array, loop the rivals
array and check if a player already has a counter or not. If not, create one for that player with a score of 0. Then simply check the winner
property to update the records. If there is a winner, increase that player's score by 3, if not, increment both players' counters by 1:
var result = arr.reduce(function(result, sub) {
var obj = sub[0];
obj.rivals.forEach(function(rival) {
result[rival] = result[rival] || 0;
});
if(obj.winner === "none") {
obj.rivals.forEach(function(rival) {
result[rival]++;
});
} else {
result[obj.winner] += 3;
}
return result;
}, {});
This can be refactored to use ES6 arrow functions like so:
let result = arr.reduce((result, {0: obj}) => {
obj.rivals.forEach(rival => result[rival] = result[rival] || 0);
if(obj.winner === "none") {
obj.rivals.forEach(rival => result[rival]++);
} else {
result[obj.winner] += 3;
}
return result;
}, {});
Example:
let arr = [[{rivals: ['player1','player2'], winner: "player1"}],[{rivals: ['player1','player3'], winner: "none"}],[{rivals: ['player2','player3'], winner: "player3"}],[{rivals: ['player1','player4'], winner: "none"}]];
let result = arr.reduce((result, {0: obj}) => {
obj.rivals.forEach(rival => result[rival] = result[rival] || 0);
if(obj.winner === "none") {
obj.rivals.forEach(rival => result[rival]++);
} else {
result[obj.winner] += 3;
}
return result;
}, {});
console.log(result);
Note: This solution doesn't produce separate variables for the counters. It instead generates an object that holds the scores which is tidier and cleaner.
Upvotes: 6
Reputation: 26537
Here is a concise method that can add them up.
const results = [
[{ rivals: ['player1','player2'], winner: "player1" }],
[{ rivals: ['player1','player3'], winner: "none" }],
[{ rivals: ['player2','player3'], winner: "player3" }],
[{ rivals: ['player1','player4'], winner: "none" }]
];
const scores = results.reduce((scores, [{ rivals, winner }]) =>
Object.assign(scores, winner == 'none'
? {
[rivals[0]]: (scores[rivals[0]] || 0) + 1,
[rivals[1]]: (scores[rivals[1]] || 0) + 1
} : { [winner]: (scores[winner] || 0) + 3 }),
{});
console.log(scores);
If you want to make sure they have 0
, you can tweak it a little bit:
const results = [
[{ rivals: ['player1','player2'], winner: "player1" }],
[{ rivals: ['player1','player3'], winner: "none" }],
[{ rivals: ['player2','player3'], winner: "player3" }],
[{ rivals: ['player1','player4'], winner: "none" }]
];
const scores = results.reduce((scores, [{ rivals, winner }]) =>
Object.assign(scores, winner == 'none'
? {
[rivals[0]]: (scores[rivals[0]] || 0) + 1,
[rivals[1]]: (scores[rivals[1]] || 0) + 1
} : {
[rivals[0]]: (scores[rivals[0]] || 0),
[rivals[1]]: (scores[rivals[1]] || 0),
[winner]: (scores[winner] || 0) + 3
}),
{});
console.log(scores);
Upvotes: 1