Click here to Skip to main content
15,848,157 members
Please Sign up or sign in to vote.
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

1 solution

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)
        AddHandler Cards.CollectionChanged, AddressOf CardCollectionChanged
        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
        RemoveHandler Cards.CollectionChanged, AddressOf CardCollectionChanged
    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

    Public Overloads Sub Reset()

        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
            Cards.Add(card)
        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

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

    Public Sub AddCardOnBottom(card As Card)
        If Not Cards.Contains(card) Then
            Cards.Add(card)
            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

    Public Sub AddCard(card As Card)
        If Cards.Contains(card) Then
            Throw New InvalidOperationException($"Hand already contains card {card}.")
        End If
        Cards.Add(card)
    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
        Cards.Add(card)
    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).
 
Share this answer
 
v5
Comments
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!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900