1

I'm making a game where each player can submit an answer on a given question and other players can vote on an answer of another player. I store these results in an array of game rounds which may look something like the following:

const roundHistory = [
  {
    question: 'question1',
    submissions: [
      {
        explanation: 'answer1',
        player: { id: 'id1', name: 'player1' },
        votes: [
          { id: 'id2', name: 'player2' },
          { id: 'id3', name: 'player3' },
        ],
      },
      {
        explanation: 'answer2',
        player: { id: 'id2', name: 'player2' },
        votes: [{ id: 'id1', name: 'player1' }],
      },
      {
        explanation: 'answer3',
        player: { id: 'id3', name: 'player3' },
        votes: [],
      },
    ],
  },
  {
    question: 'question2',
    submissions: [
      {
        explanation: 'answer1',
        player: { id: 'id1', name: 'player1' },
        votes: [
          { id: 'id2', name: 'player2' },
          { id: 'id3', name: 'player3' },
        ],
      },
      {
        explanation: 'answer2',
        player: { id: 'id2', name: 'player2' },
        votes: [{ id: 'id1', name: 'player1' }],
      },
      {
        explanation: 'answer3',
        player: { id: 'id3', name: 'player3' },
        votes: [],
      },
    ],
  },
];

As you can see there are 3 players in the game since each round (index of the roundHistory array) has 3 submissions. Each submission has a property player which represents the player who submitted the submission. And then each submission has a property votes which is an array of the players who voted for that submission. Now my question:

How can I get the total received votes per player of all rounds?


What I've tried so far... I thought, first I'd get the total received votes per player per round like so:

const roundHistory = [{question:'question1',submissions:[{explanation:'answer1',player:{id:'id1',name:'player1'},votes:[{id:'id2',name:'player2'},{id:'id3',name:'player3'},],},{explanation:'answer2',player:{id:'id2',name:'player2'},votes:[{id:'id1',name:'player1'}],},{explanation:'answer3',player:{id:'id3',name:'player3'},votes:[],},],},{question:'question2',submissions:[{explanation:'answer1',player:{id:'id1',name:'player1'},votes:[{id:'id2',name:'player2'},{id:'id3',name:'player3'},],},{explanation:'answer2',player:{id:'id2',name:'player2'},votes:[{id:'id1',name:'player1'}],},{explanation:'answer3',player:{id:'id3',name:'player3'},votes:[],},],},];

const getTotalReceivedVotesPerPlayerInRound = (round) => {
  return roundHistory[round].submissions.map((s) => ({
    player: s.player,
    totalVotes: s.votes.length,
  }));
}

console.log(getTotalReceivedVotesPerPlayerInRound(0));

But I got stuck at adding all results of all rounds together. Note that I tried to simplify all used objects such as a player. In my application these are mostly classes for which I have several utility methods. One of them is the getTotalReceivedVotesPerPlayerInRound() method that I can use on a round (index of the roundHistory array).

I expect the final result to be of the same shape as the result of my already written function: An array of objects with two properties: player (the player object) and totalVotes. E. g.:

const result = [
  {
    "player": {
      "id": "id1",
      "name": "player1"
    },
    "totalVotes": 2
  },
  {
    "player": {
      "id": "id2",
      "name": "player2"
    },
    "totalVotes": 1
  },
  {
    "player": {
      "id": "id3",
      "name": "player3"
    },
    "totalVotes": 0
  }
];
0

1 Answer 1

2

Presented below is one possible way to achieve the desired objective.

Code Snippet

const getPlayerTotalVotes = arr => (
  Object.values(
    arr.reduce(
      (acc, { submissions}) => {
        submissions.forEach(
          ({ player: { id, name }, votes }) => {
            acc[id] ??= { player: { id, name }, totalVotes: 0 };
            acc[id].totalVotes += votes.length;
          }
        )
        return acc;
      },
      {}
    )
  )
);
/* explanation of the code
method to obtain the total votes per-player for all rounds
const getPlayerTotalVotes = arr => (
  Object.values(      // extract only the values of the below intermediate result object
  arr.reduce(         // ".reduce()" to iterate and sum votes-count
    (acc, { submissions}) => {    // "acc" is the accumulator; destructure iterator
      // to directly access "submissions" array
      // then, iterate using ".forEach()" over "submissions"
      submissions.forEach(
        // destructure to access "votes" array and the particular player "id"
        ({ player: { id }, votes }) => {
          // conditionally-assign 0 if "id" not already present in "acc" 
          acc[id] ??= 0;
          // count the "votes" and add it to the "acc" prop with key as "id"
          acc[id] += votes.length;
        }
      )
      return acc;   // explicitly return "acc" for each iteration
    },
    {}        // "acc" is initialized as an empty object
  )       // implicit return of the result from ".reduce()" to caller
  )
);
*/
const roundHistory = [{
    question: 'question1',
    submissions: [{
        explanation: 'answer1',
        player: {
          id: 'id1',
          name: 'player1'
        },
        votes: [{
            id: 'id2',
            name: 'player2'
          },
          {
            id: 'id3',
            name: 'player3'
          },
        ],
      },
      {
        explanation: 'answer2',
        player: {
          id: 'id2',
          name: 'player2'
        },
        votes: [{
          id: 'id1',
          name: 'player1'
        }],
      },
      {
        explanation: 'answer3',
        player: {
          id: 'id3',
          name: 'player3'
        },
        votes: [],
      },
    ],
  },
  {
    question: 'question2',
    submissions: [{
        explanation: 'answer1',
        player: {
          id: 'id1',
          name: 'player1'
        },
        votes: [{
            id: 'id2',
            name: 'player2'
          },
          {
            id: 'id3',
            name: 'player3'
          },
        ],
      },
      {
        explanation: 'answer2',
        player: {
          id: 'id2',
          name: 'player2'
        },
        votes: [{
          id: 'id1',
          name: 'player1'
        }],
      },
      {
        explanation: 'answer3',
        player: {
          id: 'id3',
          name: 'player3'
        },
        votes: [],
      },
    ],
  },
];

console.log(
  'total votes per player\n',
  getPlayerTotalVotes(roundHistory)
);
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Inline comments added to the snippet above.

EDIT Using the given method to obtain sum of votes "per-round"

const roundHistory = [{question:'question1',submissions:[{explanation:'answer1',player:{id:'id1',name:'player1'},votes:[{id:'id2',name:'player2'},{id:'id3',name:'player3'},],},{explanation:'answer2',player:{id:'id2',name:'player2'},votes:[{id:'id1',name:'player1'}],},{explanation:'answer3',player:{id:'id3',name:'player3'},votes:[],},],},{question:'question2',submissions:[{explanation:'answer1',player:{id:'id1',name:'player1'},votes:[{id:'id2',name:'player2'},{id:'id3',name:'player3'},],},{explanation:'answer2',player:{id:'id2',name:'player2'},votes:[{id:'id1',name:'player1'}],},{explanation:'answer3',player:{id:'id3',name:'player3'},votes:[],},],},];

const getTotalReceivedVotesPerPlayerInRound = (round) => {
  return roundHistory[round].submissions.map((s) => ({
    player: s.player,
    totalVotes: s.votes.length,
  }));
}

const getTotalAllRounds = rh => (
  Object.values(
    rh.reduce(
      (acc, _, idx) => {
        getTotalReceivedVotesPerPlayerInRound(idx)?.forEach(
          ({player: { id, name}, totalVotes}) => {
            acc[id] ??= { player: {id, name}, totalVotes: 0 };
            acc[id].totalVotes += totalVotes;
          }
        );
        return acc;
      },
      {}
    )
  )
);

console.log(getTotalAllRounds(roundHistory));
.as-console-wrapper { max-height: 100% !important; top: 0 }

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.