skip to Main Content

I have two objects in javascript:

Users:

      { userId: 'id1', score: 100 },
      { userId: 'id2', score: 3 },
      { userId: 'id3', score: 2 },
      { userId: 'id4', score: 1 }

and minimumRequirements:

 { firstPlaceMinScore: 100, secondPlaceMinScore: 50, thirdPlaceMinScore: 10 }

I am trying to create a leaderboard where users should be sorted by their places if they met the requiremenents for minimum points. For example

Group1:

      { userId: 'id1', score: 3 },
      { userId: 'id2', score: 2 },
      { userId: 'id3', score: 1 }

should return:

      { userId: 'id1', place: 4 },
      { userId: 'id2', place: 5 },
      { userId: 'id3', place: 6 }

group2:

      { userId: 'id1', score: 55 },
      { userId: 'id2', score: 30 },
      { userId: 'id3', score: 52 },
      { userId: 'id4', score: 10 },
      { userId: 'id5', score: 1 }

should return:

      { userId: 'id1', place: 2 },
      { userId: 'id3', place: 3 },
      { userId: 'id2', place: 4 },
      { userId: 'id4', place: 5 },
      { userId: 'id5', place: 6 }

I have written the following function but i can’t get around the filtering of leaders part, they are messing up the count:

function getLeaderboard(users, minScores) {
    let leaderboard = [];
    let formattedMinScores = Object.values(minScores);

    const sortedUsers = users.sort((a, b) => b.score - a.score);

    loop1: for (let i = 0; i < sortedUsers.length; i++) {
      let currentPlace = i + 1;
      loop2: for (let j = 0; j < formattedMinScores.length; j++) {
        ++currentPlace;
        if (sortedUsers[i].score >= formattedMinScores[j]) {
          
          currentPlace = j + 1;
          break loop2;
        }
      }
      leaderboard.push({
        place: currentPlace,
        userId: sortedUsers[i].userId
      });
    }

    console.log(leaderboard);
    return leaderboard;
  }

2

Answers


  1. Here is a solution: you start at place 0 and for each user, you increment the place by 1. You also increment it by the number of minimum required scores that are above the user’s score (s > user.score), as long as those minimum score are not for a place above the current place (i+1 >= currentPlace)

    let group1 = [
        { userId: 'id1', score: 55 },
        { userId: 'id2', score: 30 },
        { userId: 'id3', score: 52 },
        { userId: 'id4', score: 10 },
        { userId: 'id5', score: 1 }
    ]
    
    let group2 = [
        { userId: 'id1', score: 3 },
        { userId: 'id2', score: 2 },
        { userId: 'id3', score: 1 }
    ]
    
    let minScores = { firstPlaceMinScore: 100, secondPlaceMinScore: 50, thirdPlaceMinScore: 10 }
    
    function getLeaderboard(users, minScores) {
        let leaderboard = [];
        let formattedMinScores = Object.values(minScores);
        const sortedUsers = users.sort((a, b) => b.score - a.score);
    
        let currentPlace = 0
        for (let user of sortedUsers) {
            currentPlace += 1 + formattedMinScores.filter((s, i) => s > user.score && i+1 >= currentPlace).length; 
            leaderboard.push({
                place: currentPlace,
                userId: user.userId
            });
        }
    
        console.log(leaderboard);
        return leaderboard;
    }
    
    getLeaderboard(group1, minScores)
    getLeaderboard(group2, minScores)
    Login or Signup to reply.
  2. You can sort the scores first then iterate through the positional mins.

    Note: I changed your placement min object into an indexable array.

    const minScores = [100, 50, 10];
    
    const leaderboardPositions = (group) => {
      const sorted = group
        .map(({ userId, score }, index) => ({ userId, score, index }))
        .sort((a, b) => b.score - a.score || a.index - b.index);
      let scoreIndex = 0;
      for (let i = 0; i < sorted.length; i++) {
        const player = sorted[i];
        while (player.score < minScores[scoreIndex] && scoreIndex < minScores.length) {
          scoreIndex++;
        }
        player.place = scoreIndex + 1;
        scoreIndex++;
      }
      return sorted.map(({ userId, place }) => ({ userId, place }));
    };
    
    const
      group1 = [
        { userId: 'id1', score: 3 },
        { userId: 'id2', score: 2 },
        { userId: 'id3', score: 1 }
      ],
      group2 = [
        { userId: 'id1', score: 55 },
        { userId: 'id2', score: 30 },
        { userId: 'id3', score: 52 },
        { userId: 'id4', score: 10 },
        { userId: 'id5', score: 1 }
      ];
    
    console.log(leaderboardPositions(group1));
    console.log(leaderboardPositions(group2));
    .as-console-wrapper { top: 0; max-height: 100% !important; }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search