I'm trying to create a leaderboard system by using a merge sort algorithm that sorts the scores in ascending order and then sorts the usernames by their score. I then use a for loop that displays the scores in descending order. The code in the image works perfectly fine when each user has a unique score and duplicate scores do not exist. However, I am having a problem when more than one user has the same score (i.e. there are duplicate scores).
For example, if two users have the same score (in this case 5), the wrong username is displayed. I believe this is because it only looks at the first occurrence of the sorted score. Hence, it's overwriting the original name. Is there any way I can skip the first occurrence of the duplicate number after it has been visited?
string[] UsernameAndScoresArray = System.IO.File.ReadAllLines(@"UsernamesAndScores.txt");
string[] UnsortedUsernamesArray = new string[UsernameAndScoresArray.Length];
int[] UnsortedScoresArray = new int[UsernameAndScoresArray.Length];
string UsernameAndScore = "";
string Username = "";
int Score = 0;
int position = 0;
for (int i = 0; i < UsernameAndScoresArray.Length; i++)
{
//Locates the username and scores and stores them in an 'unsorted array'
UsernameAndScore = UsernameAndScoresArray[i];
position = UsernameAndScore.IndexOf(':');
Username = UsernameAndScore.Substring(0, position);
UnsortedUsernamesArray[i] = Username;
position = UsernameAndScore.IndexOf(':');
Score = int.Parse(UsernameAndScore.Remove(0, position + 1));
UnsortedScoresArray[i] = Score;
}
//Sorts the Scores in ascending order using the merge sort algorithm
SortedArray = MergeSort(UnsortedScoresArray);
SortedUsernames = new string[SortedArray.Length];
for (int i = 0; i < UnsortedScoresArray.Length; i++)
{
for (int a = 0; a < SortedArray.Length; a++)
{
if (UnsortedScoresArray[i] == SortedArray[a])
{
//The usernames are sorted based on the scores
SortedUsernames[a] = UnsortedUsernamesArray[i];
}
}
}
int place = 0;
for (int i = SortedArray.Length - 1; i >= 0; i--)
{
//The place, username and number of points are displayed in descending order
place++;
Username = SortedUsernames[i];
Score = SortedArray[i];
ListBoxLeaderBoardPlaceAndUser.Items.Add(place + ": " + Username);
ListBoxLeaderboardScore.Items.Add(Score);
}
//This is an example of the error
UnsortedScoresArray[] = {46, 7, 5, 10, 5}
UnsortedUsernamesArray[] = {User1, User2, User3, User4, User5}
SortedScoresArray[] = {5, 5, 7, 10, 46}
SortedUsernamesArray[] = {User5, User5, User2, User4, User1}
It should say SortedUsernamesArray[] = {User3, User5, User2, User4, User1}
How do you skip a number which you've already visited in an array?
By remembering the position, for example, in a HashSet
. Here's how I'd adapt your code to do that:
var usedAlready = new HashSet<int>();
for (int a = 0; a < SortedArray.Length; a++)
{
for (int i = 0; i < UnsortedScoresArray.Length; i++)
{
if (UnsortedScoresArray[i] == SortedArray[a] && !usedAlready.Contains(i))
{
SortedUsernames[a] = UnsortedUsernamesArray[i];
usedAlready.Add(i);
// We already found the user for position a, no need to continue the inner loop.
break;
}
}
}
Note that I've switched your loops around (first a
(through SortedArray), then i
).