Reputation: 99
I have to make this program that sorts the high scores of a game and then displays them biggest to smallest with the username USING LISTS. So far i have written:
Public highscore As New List(Of HighScores)
highscore.Add(New HighScores("Jeremias", 6))
highscore.Add(New HighScores("Tom", 1))
highscore.Add(New HighScores("sdf", 5))
highscore.Add(New HighScores("asfd", 1))
highscore.Sort()
highscore.Reverse()
Console.WriteLine("------High Scores-----")
For Each scores In highscore
Console.WriteLine(scores)
Next
Console.WriteLine("----------------------")
And the HighScores Class:
Public Class HighScores
Public name As String
Public score As Integer
Public Sub New(ByVal name As String, ByVal score As Integer)
Me.name = name
Me.score = score
End Sub
Public Overrides Function ToString() As String
Return String.Format("{0}, {1}", Me.name, Me.score)
End Function
End Class
Usually i would just use .Sort() and .Reverse() to sort the list, but in this case i don't think i can do this. Any ideas how i can rewrite this/just sort the list easily?
Upvotes: 2
Views: 5263
Reputation: 54417
You can specify how to sort a List(Of T)
in various ways. The simplest would be like so:
highscore.Sort(Function(x, y) y.score.CompareTo(x.score))
That uses the overload of Sort
that takes a Comparison(Of T)
delegate and uses a Lambda expression for that delegate. Note that the Lambda parameters are x
and y
and the body calls CompareTo
on the score
of y
. That is critical because that's what makes the sort happen in descending order and negates the need to call Reverse
.
Note that you could use a named method instead of a Lambda. Such a method would look like this:
Private Function CompareHighScoresByScoreDescending(x As HighScores, y As HighScores) As Integer
Return y.score.CompareTo(x.score)
End Function
The code to sort would then look like this:
highscore.Sort(AddressOf CompareHighScoresByScoreDescending)
When comparing objects for sorting purposes, the convention is to use -1, 0 and 1 to represent relative positions. That's what CompareTo
does and thus that's what our comparison method does here. If the object you call CompareTo
on is conceptually less the object you pass in then the result is -1. 1 means the first object is greater than the second and 0 means they are equal. That method could be rewritten like so:
Private Function CompareHighScoresByScoreDescending(x As HighScores, y As HighScores) As Integer
If y.score < x.score Then
Return -1
ElseIf y.score > x.score Then
Return 1
Else
Return 0
End If
End Function
It's obviously more succinct to use the existing IComparable
implementation of the Integer
type though, i.e. that CompareTo
method.
By the way, your code could use some improvements in other areas. Firstly, HighScores
is not an appropriate name for that class. It represent a single thing so the name should not be plural and it doesn't actually represent a high score in and of itself. A more appropriate name would be PlayerScore
as that more accurately describes what it represents.
Secondly, your List
variable actually does represent more than one object, i.e. a list that contains multiple items, so it's name should be plural. It also does actually represent high scores so it should be named highScores
.
Finally, it is almost universally bad practice to expose member variables publicly. You should absolutely be using properties in that class:
As a bonus, if you're using VS 2015 or later then you can also replace String.Format
with string interpolation.
Public Class PlayerScore
Public Property Name As String
Public Property Score As Integer
Public Sub New(name As String, score As Integer)
Me.Name = name
Me.Score = score
End Sub
Public Overrides Function ToString() As String
Return $"{Name}, {Score}"
End Function
End Class
Upvotes: 4