This coding puzzle is incredible

This is such a tricky coding puzzle, you won’t believe the algorithm I had to make to solve it.

JavaScript
function addToLeaderboard(player, ranked) { } // Can you write the code for the addToLeaderboard() function? console.log(addToLeaderboard([80, 60, 60, 10], [90])); // [1] console.log(addToLeaderboard([80, 60, 60, 10], [90, 100])); // [2, 1] console.log( addToLeaderboard([80, 60, 60, 10], [90, 60, 5]) // [1, 3, 5] );

So first let’s understand what the puzzle is about.

You have a function that takes two inputs:

  • a player array — a list of player scores
  • a ranked array — a list of scores already on the leaderboard

So each of the scores in ranked are ranked.

For example:

  • Player scores: 80, 60, 10
  • Resulting ranking: 1, 2, 3 — respectively

Ignoring how bad you have to be get 10 in any sort of game where others are scoring 80…

What if the players what if the players are tied? For example:

  • 80, 60, 60, 10

Result ranking:

  • 1, 2, 2, 3

You give the same rank to the tied players, and then the next players get the rank after that.

So what does the function do? It adds the new batch of scores in player to the leaderboard in ranked — which ranks them

The function will return an array of the new ranks of these new scores that just got added.

For example if the player array is [90] — just one item, it will return [1] — the scores are now 90, 80, 60, 10.

So if the array is [90, 60, 5], what will it return?

It will be [1, 3, 5] — NOT [1, 2, 4] or [1, 2, 5] like you might mistakenly guess.

So this is where we are:

JavaScript
function addToLeaderboard(ranked, players) { } console.log(addToLeaderboard([80, 60, 60, 10], [90])); // [1] console.log(addToLeaderboard([80, 60, 60, 10], [90, 100])); // [2, 1] console.log( addToLeaderboard([80, 60, 60, 10], [90, 60, 5]) // [1, 3, 5] );

So how we go about it? How do we get the ranks of the newly added scores.

I can see that data from both arrays are being combine into each other to give the updated leaderboard data.

You can also see that this is a leaderboard of scores — which clearly means sorting is going on…

Can you see where this is going?

Initially, I thought it was going to be a highly sophisticated algorithm.

But after this simple thought exercise, what we need to do is so obvious.

  1. Merge the player and ranked arrays.
  2. Sort the result of the new array
  3. Get the position of each score in player from the sorted array

Let’s merge the arrays:

JavaScript
// ranked: 80, 60, 10 // players: 90, 60, 5 const merged = [...ranked, ...players]; // merged: 80, 60, 10, 90, 60, 5

Now sorting — since the highest score comes first, we need to sort it by descending order:

JavaScript
const sorted = merged.sort((a, b) => b - a); // sorted: 80

How about getting the positions for each score from player in the new leaderboard?

Of course we have the indexOf() method.

But if you just used this you’d be way off the mark… (get it?)

indexOf returns the zero-based index — first element has index of 0, second of 1, and so on…

JavaScript
const rank = sorted.indexOf(players[0]); // 0

To get the leaderboard ranks, we need the one-based index — first element should give 1.

So obviously we fix easily with a +1.

JavaScript
const rank = sorted.indexOf(players[0]) + 1; // 1

So what’s left now is doing this for each item in the players array — a perfect use case for… ?

map():

JavaScript
const ranks = players.map( (score) => sorted.indexOf(score) + 1 );

So now let’s test the full function:

JavaScript
function addToLeaderboard(ranked, players) { const merged = [...ranked, ...players]; const sorted = merged.sort((a, b) => b - a); const ranks = players.map( (score) => sorted.indexOf(score) + 1 ); return ranks; } console.log(addToLeaderboard([80, 60, 60, 10], [90])); // [1] console.log(addToLeaderboard([80, 60, 60, 10], [90, 100])); // [2, 1] console.log( addToLeaderboard([80, 60, 60, 10], [90, 60, 5]) // [1, 3, 5] );

If it works we should get the results in the comments:

No! What happened with the last test case?

It’s giving [1, 3, 7] instead of [1, 3, 5]?

It seems like the last score (5) is being pushed down by 2 from 5 to 7?

What do you think could be causing this?

Yes! The multiple 60‘s in the array is affecting the result that indexOf gives.

To fix this we need to remove the duplicates after the merge.

A perfect job for Set():

JavaScript
function addToLeaderboard(ranked, players) { const merged = [...ranked, ...players]; const unique = [...new Set(merged)]; const sorted = unique.sort((a, b) => b - a); const ranks = players.map( (score) => sorted.indexOf(score) + 1 ); return ranks; }

Now let’s try that again:

Perfect.



Leave a Comment

Your email address will not be published. Required fields are marked *