0

I have a function that takes Card objects and needs to sort them by their string value in a custom order. Each card can be any number from 2 to 10, or J, Q, K, or A. I want my function to sort the cards in this order: 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A.

However, if I try to sort them with OrderBy(x => x.Value) , it will sort them by string. I have the function GetRankDictionary because I thought it would be helpful but I don't see If there is a way I could use it in a lambda expression for OrderBy's arguements.

class Program
{
    public class Card
    {
        public string Value;
        public string Suit;

        public Card(string value, string suit)
        {
            Value = value;
        }
    }
    static void Main(string[] args)
    {
        var cards = new List<Card>() {  new Card("J", "Hearts"), new Card("8", "Hearts"), new Card("3", "Hearts"),
                                        new Card("6", "Hearts"), new Card("9", "Hearts"), new Card("7", "Hearts"), 
                                        new Card("K", "Hearts"), new Card("A", "Hearts"), new Card("2", "Hearts")};
        cards = SortCards(cards);
    }

    public static List<Card> SortCards(List<Card> cards)
    {
        var RankDictionary = GetCardRankDictionary();

        // How to custom sort the cards in LINQ indicated by RankDictionary?
        cards = cards.OrderBy(x => x.Value).ToList();

        foreach (Card c in cards)
            Console.WriteLine(c.Value);

        return cards;
    }

    public static Dictionary<string, int> GetCardRankDictionary()
    {
        var dict = new Dictionary<string, int>();
        var values = new string[] {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"};

        var index = 2;
        foreach (string s in values)
            dict.Add(s, index++);

        return dict;

    }

}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
ArmorCode
  • 739
  • 4
  • 15
  • 33
  • 1
    You could add the property `public int NumValue` to the class Cards that represents the Value of the card with an int. Numbers "2" to "9" would be their according int value, and "J" == 11, "Q" == 12, etc., set in the constructor with a switch. Btw, did you left out "10" intentionally? Another solution would be a Comparer: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.comparer-1?view=net-5.0 – cad Dec 14 '20 at 23:46
  • 1
    Just give your `Card` an extra property of `Rank` and then sort on that – JohanP Dec 14 '20 at 23:46
  • @JohanP suggestion is simple and you're going to need that property or another list of the ranks. Some people prefer to do this using the `IComparer` and `IComparable` interfaces, https://stackoverflow.com/a/26868916/495455 - then you can use the built-in sort function. – Jeremy Thompson Dec 14 '20 at 23:52
  • @cad I left out 10 accidentally. Thanks for noticing. – ArmorCode Dec 14 '20 at 23:53

1 Answers1

3

It's really quite straightforward. Your code was almost there.

Try this:

public static List<Card> SortCards(List<Card> cards)
{
    var RankDictionary = GetCardRankDictionary();

    cards = cards.OrderBy(x => RankDictionary[x.Value]).ToList();

    foreach (Card c in cards)
        Console.WriteLine(c.Value);

    return cards;
}

public static Dictionary<string, int> GetCardRankDictionary() =>
    new string[] { "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A" }
        .Select((x, n) => (x, n))
        .ToDictionary(z => z.x, z => z.n);

Running that on your sample data gives me:

2
3
6
7
8
9
J
K
A
Enigmativity
  • 113,464
  • 11
  • 89
  • 172