15,848,157 members
1.00/5 (1 vote)
See more:
I want the result of my query ordered descending for card.CardRatedValue.
How to do this for my example?

What I have tried:

```If TrumpCardID <> 4 And suit = TrumpCardID Then
Return hand.Cards _
.OrderBy(Function(card) card.CardRatedValue) _
.Where(Function(card) card.CardType = suit) _
.Where(Function(card) card.CardRatedValue >= 0) _
.FirstOrDefault
End If
```
Posted
Updated 14-Jan-23 14:11pm

## Solution 1

You should be sorting in descending order as we did with the `CardDeck`. We need to add a `SorterDescending` class:
VB.NET
```Public Class CardSorterDescending
Implements IComparer(Of Card)

Public Sub New(Optional sortBy As CardSortType = CardSortType.SuitThenKind)
Me.SortBy = sortBy
End Sub

Property SortBy As CardSortType

Public Function Compare(x As Card, y As Card) As Integer Implements IComparer(Of Card).Compare
Select Case Me.SortBy
Case CardSortType.KindOnly
Return y.Kind.CompareTo(x.Kind)
Case CardSortType.SuitOnly
Return y.Suit.CompareTo(x.Suit)
Case CardSortType.SuitThenKind
If x.Suit <> y.Suit Then
Return y.Suit.CompareTo(x.Suit)
End If
Return y.Kind.CompareTo(x.Kind)
Case CardSortType.KindThenSuit
If y.Kind <> y.Kind Then
Return y.Kind.CompareTo(x.Kind)
End If
Return y.Suit.CompareTo(y.Suit)
Case Else
Throw New NotImplementedException(\$"CardOrderMethod {SortBy} is not implemented.")
End Select
End Function
End Class```

As there are a number of common methods, including the `Cards` collection, we can create a `CardsBase` abstract class (DRY principle - Don't Repeat Yourself):
VB.NET
```Imports System.Collections.ObjectModel
Imports System.Collections.Specialized

Public MustInherit Class CardsBase : Inherits ObservableObject : Implements IDisposable

Public Sub New()
Cards = New ObservableCollection(Of Card)
Reset()
End Sub

Public ReadOnly Property Cards As ObservableCollection(Of Card)

Public ReadOnly Property Count As Integer
Get
Return Cards.Count
End Get
End Property

Private Sub CardCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
OnPropertyChanged(NameOf(Count))
End Sub

Public Overridable Sub Reset()
Cards.Clear()
End Sub

Public Sub Sort()
Dim sorted = New List(Of Card)(Cards.ToList())
sorted.Sort()
ReorderCards(sorted)
End Sub

Public Sub SortDescending()
Dim sorted = New List(Of Card)(Cards.ToList())
sorted.Sort(New CardSorterDescending)
ReorderCards(sorted)
End Sub

Public Sub Sort(comparer As IComparer(Of Card))
Dim sorted = New List(Of Card)(Cards.ToList())
sorted.Sort(comparer)
ReorderCards(sorted)
End Sub

Public Sub SortBy(ByVal Optional sortType As CardSortType? = Nothing)
If sortType Is Nothing Then
Sort()
Else
Sort(New CardSorter With {
.SortBy = CType(sortType, CardSortType)
})
End If
End Sub

Public Sub SortByDescending(ByVal Optional sortType As CardSortType? = Nothing)
If sortType Is Nothing Then
SortDescending()
Else
Sort(New CardSorterDescending With {
.SortBy = CType(sortType, CardSortType)
})
End If
End Sub

Protected Sub ReorderCards(ordered As List(Of Card))
For index As Integer = 0 To ordered.Count - 1
Cards.Move(Cards.IndexOf(ordered(index)), index)
Next
End Sub

Public Sub Dispose() Implements IDisposable.Dispose
End Sub

End Class```

Note: There is now a new `SortDescending` subroutine. This is a default sorter and it uses the new `CardSorterDescending` class.

The updated `CardDeck` class:
VB.NET
```Public Class CardDeck : Inherits CardsBase

Public Sub New()
MyBase.New()
Reset()
End Sub

MyBase.Reset()

Dim cardCollection = [Enum].GetValues(GetType(Suit)) _
.Cast(Of Suit)() _
.SelectMany(Function(__) [Enum].GetValues(GetType(Kind)) _
.Cast(Of Kind)(),
Function(suit, kind) New With {suit, kind}) _
.Select(Function(card) New Card(card.kind, card.suit))

For Each card As Card In cardCollection
Next

End Sub

Public Function DrawCardAt(index As Integer) As Card
If index < 0 OrElse index >= Count Then
Throw New ArgumentOutOfRangeException(NameOf(index))
End If
Dim card As Card = Cards(index)
Cards.RemoveAt(index)
Return card
End Function

Public Function DrawTopCard() As Card
Return DrawCardAt(0)
End Function

Public Function DrawBottomCard() As Card
Return DrawCardAt(Count - 1)
End Function

Public Function DrawRandomCard() As Card
Dim random As Random = New Random()
Dim index As Integer = random.[Next](Count)
Return DrawCardAt(index)
End Function

If Cards.Contains(card) Then
Throw New InvalidOperationException(\$"Deck already contains card {card}.")
End If
Cards.Insert(0, card)
End Sub

If Not Cards.Contains(card) Then
Return
End If

Throw New InvalidOperationException(\$"Deck already contains card {card}.")
End Sub

Public Sub Shuffle()
ReorderCards(Cards.OrderBy(Function(x) Guid.NewGuid()).ToList())
End Sub

End Class```

And the new `Hand` class:
VB.NET
```Public Class Hand : Inherits CardsBase

Private nameValue As String

Public Sub New(name As String)
MyBase.New()
Me.Name = name
End Sub

Public Property Name As String
Get
Return nameValue
End Get
Set
SetValue(nameValue, Value)
End Set
End Property

If Cards.Contains(card) Then
Throw New InvalidOperationException(\$"Hand already contains card {card}.")
End If
End Sub

Public Sub RemoveCard(card As Card)
If Not Cards.Contains(card) Then
Throw New InvalidOperationException(\$"Hand does not contain card {card}.")
End If
End Sub

End Class```

Now if you want to do custom Sorting Ascending/Descending:

1. The `CardDeck`
VB
`Deck.SortByDescending(CardSortType.SuitThenKind)`

2. The `Hand`
VB
`Hand.SortByDescending(CardSortType.SuitThenKind)`

But to answer your original question, you would use `OrderByDescending` and `ThenByDescending`:
VB
`hand.Cards = hand.Cards.OrderByDescending(Function(n) n.Suit).ThenByDescending(Function(n) n.Kind)`

If the collection is an `ObservableCollection`, this won't work as you will break the data binding. You need to use a temporary collection, sort that, clear the `ObserableCollection`, then reload it. I do it slightly differently: Temp collection, sort, then I have a `ReorderCards` subroutine that moves the items to the newly sorted order. See above how I do it (If you add a small delay factor, and animation, you could make the cards move to their new positions. That is a more advanced topic outside the scope of Q&A).

v5
Jo_vb.net 14-Jan-23 19:40pm
Good to have this new sorter class, thank you.

For my example .OrderByDescending seems to work.

And a side note:

These Linq queries in HandExtensions Module seem to be the solution for my search regarding a concept to generate rules for my cards game.

Great framework you shared!
Graeme_Grant 14-Jan-23 20:02pm
No problems ... I spoke about animation ... here is what it would look like: Animated card Sorting[^]

As for Linq, here is a great learning resource: LINQSamples | LINQ 101 Query and Lambda Expression Samples[^]
Jo_vb.net 15-Jan-23 8:19am
Fine animation - does this mean your game runs in a browser?
Graeme_Grant 15-Jan-23 8:28am
No, that is WPF.
Maciej Los 16-Jan-23 16:11pm
5ed!