broodplank
broodplank

Reputation: 41

Get top 5 scores/names from list

I am adding a function to keep track of scores for a small game I made. I want to get the top 5 scores (including name for that score) from a file that contains the scores.

The format of the saved scores is:

[name]-[score]

The scores and names are stored in 2 lists, which I parse this way:

string scores = File.ReadAllText(Environment.GetEnvironmentVariable("TEMP") + "/scores");
string[] splitscores = scores.Split('\n');

foreach (string entry in splitscores)
{
    string replace = entry.Replace("[", "").Replace("]", "");
    string[] splitentry = replace.Split('-');

    if (splitentry.Count() > 1)
    {
        scorenames.Add(splitentry[0]);
        scorelist.Add(Int32.Parse(splitentry[1]));
    }
}

Then I retrieve #1 player by using:

int indexMax
    = !scorelist.Any() ? -1 :
    scorelist
    .Select((value, index) => new { Value = value, Index = index })
    .Aggregate((a, b) => (a.Value > b.Value) ? a : b)
    .Index;

lblhighscore1.Text = "#1:  " + scorelist[indexMax] + " by " + scorenames[indexMax];

How can I set the remaining 4 players assuming this is my scorelist:

[broodplank]-[12240]
[flo]-[10944]
[bill]-[11456]
[tony]-[9900]
[benji]-[7562]

I've figured I could do a descending sort of the score list, but that wouldn't cover the changes in the indexes of the usernames list, what is the best approach for this?

Upvotes: 3

Views: 786

Answers (2)

broodplank
broodplank

Reputation: 41

In addition to MarcinJuraszeks useful answer, some small things that I came across using his solution which I decided to share.

First problem was with the class which threw me the following error

'Score': member names cannot be the same as their enclosing type

Changing the case of "s" fixed it

class Score
{
    public string Name { get; private set; }
    public int score { get; private set; }

    public Score(string name, int Score)
    {
        Name = name;
        score = Score;
    }
}

And calling the individual values can be done with Linq

string numberOne = topScores.Skip(0).First().score
string numberTwo = topScores.Skip(1).First().score 

and so on

Upvotes: 0

MarcinJuraszek
MarcinJuraszek

Reputation: 125650

Best approach? Don't use parallel collections anti-pattern.

Instead of having 2 lists, create a class that can hold both the name and the score together

class Score
{
    public string Name { get; private set; }
    public int Score { get; private set; }

    public Score(string name, int score)
    {
        Name = name;
        Score = score;
    }
}

and have just one list

List<Score> scores = new List<Score>();
foreach (string entry in splitscores)
{
    string replace = entry.Replace("[", "").Replace("]", "");
    string[] splitentry = replace.Split('-');

    if (splitentry.Count() > 1)
    {
        scores.Add(new Score(splitentry[0], Int32.Parse(splitentry[1]))
    }
}

You can easily order by one property and because the whole object will be reordered you'll keep the names in the right order without any additional code:

topScores = scores.OrderByDescending(x => x.Score).Take(5);

Upvotes: 9

Related Questions