[VB.NET] Sorting Array of Custom Class objects
Lets say you are writing a card game and you need to be able to sort a player's cards into numerical and suit order.
You have written a PlayingCard class, and you have to find a way of sorting by these 2 criteria.
The .Net (OOP) way is to make that class implement the IComparable interface. This simply adds a function that decides if one class instance is 'greater then, less than or equal to' another instance of the same class. Write your sorting rules into this function body and that is. You don't have to worry about moving items into the right places in the array, or type conversion problems, or anything like that. The Array.Sort() function calls your implementation of the IComparable interface and communicates directly with it without your intervention.
Here is a nice example I just cooked up.
(The important parts are highlighted in red).
Code:
Module Module1
Sub Main()
Dim Deck() As PlayingCard = New PlayingCard(99) {}
Dim i As Integer
Dim r As Random = New Random
For i = 0 To 99 'randomize the array
Deck(i) = New PlayingCard(r.Next(PlayingCard.CARDVALUE.Ace, PlayingCard.CARDVALUE.King + 1), r.Next(PlayingCard.CARDSUIT.Spades, PlayingCard.CARDSUIT.Diamonds + 1))
Next i
PlayingCard.AcesHigh = True
Array.Sort(Deck)
For i = 0 To 99
Console.WriteLine(Deck(i))
Next i
Console.ReadLine()
End Sub
End Module
Public Class PlayingCard
Implements IComparable 'IMPORTANT
#Region "Game Specific"
#Region "Enums"
Public Enum CARDVALUE
Ace = 1
Two = 2
Three = 3
Four = 4
Five = 5
Six = 6
Seven = 7
Eight = 8
Nine = 9
Ten = 10
Jack = 11
Queen = 12
King = 13
HighAce = 14
End Enum
Public Enum CARDSUIT
Spades = 0
Hearts = 1
Clubs = 2
Diamonds = 3
End Enum
#End Region
#Region "Shared"
Public Shared AcesHigh As Boolean = False
#End Region
#Region "Member Data"
Private _Value As CARDVALUE = CARDVALUE.Ace
Private _Suit As CARDSUIT = CARDSUIT.Spades
#End Region
Public Property Value() As CARDVALUE
Get
Return _Value
End Get
Set(ByVal RHS As CARDVALUE)
If RHS = CARDVALUE.HighAce Then Throw New ArgumentException("Cannot set Value to HighAce directly, set Value to Ace and set AcesHigh variable to True")
_Value = RHS
End Set
End Property
Public Property Suit() As CARDSUIT
Get
Return _Suit
End Get
Set(ByVal RHS As CARDSUIT)
_Suit = RHS
End Set
End Property
Public ReadOnly Property IsHighAce() As Boolean
Get
Return (_Value = CARDVALUE.Ace) And AcesHigh
End Get
End Property
Public ReadOnly Property IsRoyalty() As Boolean
Get
Return (_Value >= CARDVALUE.Jack) And (_Value <= CARDVALUE.King)
End Get
End Property
Public Overrides Function ToString() As String
Dim s As String
Select Case _Value
Case CARDVALUE.Ace
s = "Ace of "
Case CARDVALUE.Two
s = "Two of "
Case CARDVALUE.Three
s = "Three of "
Case CARDVALUE.Four
s = "Four of "
Case CARDVALUE.Five
s = "Five of "
Case CARDVALUE.Six
s = "Six of "
Case CARDVALUE.Seven
s = "Seven of "
Case CARDVALUE.Eight
s = "Eight of "
Case CARDVALUE.Nine
s = "Nine of "
Case CARDVALUE.Ten
s = "Ten of "
Case CARDVALUE.Jack
s = "Jack of "
Case CARDVALUE.Queen
s = "Queen of "
Case CARDVALUE.King
s = "King of "
End Select
Select Case _Suit
Case CARDSUIT.Spades
s &= "Spades"
Case CARDSUIT.Hearts
s &= "Hearts"
Case CARDSUIT.Clubs
s &= "Clubs"
Case CARDSUIT.Diamonds
s &= "Diamonds"
End Select
Return s
End Function
#End Region
Public Sub New(ByVal itsValue As CARDVALUE, ByVal itsSuit As CARDSUIT)
Value = itsValue
Suit = itsSuit
End Sub
Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo
'where the Sorting logic is run
'Basically says: "if ME greater than the obj card then return 1, if equal return 0 and if less than, return -1"
If Not TypeOf obj Is PlayingCard Then Throw New ArgumentException 'make sure obj is a card before continuing
Dim temp As PlayingCard = CType(obj, PlayingCard)
Dim vObj As CARDVALUE = temp.Value
Dim vMe As CARDVALUE = _Value
Dim s As CARDSUIT = temp.Suit
If _Suit < s Then 'suits take precedence
Return -1
ElseIf _Suit > s Then
Return 1
Else
If AcesHigh Then 'some games require aces to have a value of 14 rather than 1, hence "Aces High"
If vObj = CARDVALUE.Ace Then vObj = CARDVALUE.HighAce
If vMe = CARDVALUE.Ace Then vMe = CARDVALUE.HighAce
End If
'if suite are the same, check the card numbers...
If vMe < vObj Then
Return -1
ElseIf vMe > vObj Then
Return 1
Else
Return 0 'cards are identical (if you are using more than 1 deck deck of cards in a program)
End If
End If
End Function
End Class
Copy this code into a console app and run it. It also demonstrates the overriding of the Tostring() function.
The output looks like this...
Re: [VB.NET] Sorting Array of Custom Class objects