1

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!

2
  • 2
    What have you tried so far? Please share some code. Commented Jul 16, 2018 at 17:33
  • 1
    Whenever you think you need numbered variables like that, you should be using an array or object, not separate variables. Commented Jul 16, 2018 at 17:38

2 Answers 2

6

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.

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

Comments

1

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

5 Comments

No mention of supported browsers with Object.assign or a polyfill?
Most browsers now support Object.assign now. SO isn't for holding hands for every little detail. Most developers know they may need to transpile or polyfill something. It's not something that needs to be mentioned on every single answer that uses slightly modern features.
You're assuming everyone's knowledge domain of transpilation and supported features, which is just wrong. SO isn't for holding hands, but it IS for creating as accurate/complete answers as possible, which would include mentioning that Object.assign isn't supported in every browser and can require a polyfill.
If every question that used Object.assign, Object.create, arrow functions, classes, etc., listed out all of that information, answers would be 10 pages long. Sites like caniuse.org exist for a reason.
Please note that Object.assign is not fully supported in every browser. Use caniuse.org for a compatibility chart doesn't seem like 10 pages long, but oh well, let's just paste code and not try to help people

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.