2

As a project I'm creating a poker game.

I have an array of Cards, each of which has a value CardValue given by the enum below. I want a dictionary Dictionary<CardValue, int> to contain the number of occurences of each CardValue in the array of Cards.

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
}

I have created this dictionary manually, and it only has thirteen key value pairs so wasn't too expensive... but if I had a far larger enum I would want a more efficient way to create this dictionary (from a quick scan of the web you can use ToDictionary() for IEnumarables, but not sure if relevant).

Note for question similarity: This got flagged for being too similar to:

Enum to Dictionary<int, string> in C#

However in this question they had a dictionary of type Dictionary<int, string> whereas I want to retain the enum in the key of the dictionary for referencing purposes, and don't want this replaced by an int. E.g. For checking the number of queens that occur in an array of cards I want to check CardValueCount[CardValue.Queen] and not CardValueCount[12] for readability.

The code I have at the moment is here (edit: removed switch statement as suggested):

    public Card[] Cards {get; set;}
    private Dictionary <CardValue, int> CardValueCount
    {
        get
        {
            var cardValueCount = new Dictionary<CardValue, int>()
            {
                { CardValue.Ace, 0},
                { CardValue.Two, 0},
                { CardValue.Three, 0},
                { CardValue.Four, 0},
                { CardValue.Five, 0},
                { CardValue.Six, 0},
                { CardValue.Seven, 0},
                { CardValue.Eight, 0},
                { CardValue.Nine, 0},
                { CardValue.Ten, 0},
                { CardValue.Jack, 0},
                { CardValue.Queen, 0},
                { CardValue.King, 0}
            };
            if (Cards.Length < 1 || Cards == null)
            {
                return cardValueCount;
            }
            else
            {
                foreach (Card card in Cards)
                {
                    cardValueCount[card.Value]++;
                }
                return cardValueCount;
            }
        }
    }

(Edit 2) Removed switch statement as suggested.

Note 1: Haven't actually ran this yet so there may be something that wouldn't work as is!

Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
Adam Cook
  • 31
  • 2
  • A quick note: you could replace your entire `switch` with `cardValueCount[card.Value]++;` – afarrag Jan 02 '23 at 03:47
  • of course! Should've seen that from the off. Thanks @afarrag ! – Adam Cook Jan 02 '23 at 04:22
  • You're welcome, buddy. Note also that enum elements are in fact integers. The first enum element is assigned value zero, and each following element is the pervious+1. So, in your example, `CardValue.Ace` is `0` and `CardValue.Two` is `1`, and so on. Hope this helps! – afarrag Jan 02 '23 at 04:35
  • 1
    @afarrag from the [docs](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum): *"By default, the associated constant values of enum members are of type `int`; they start with zero and increase by one following the definition text order. You can explicitly specify any other [integral numeric](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types) type as an underlying type of an enumeration type."* – Theodor Zoulias Jan 02 '23 at 04:39
  • @afarrag does my updated edit with the enum and the example with the number of occurences of the queen explain why I want the dictionary in this format? – Adam Cook Jan 02 '23 at 05:15
  • You can keep the enum (which I blindly assumed its order and value, thanks @TheodorZoulias for correcting me), and use integers at the same time. For instance, initializing your dictionary doesn't have to be this long. You could loop from 1 to 13 and use the loop counter as the dictionary's key. – afarrag Jan 02 '23 at 05:24

2 Answers2

2

Resuing the @Theodor's answer.

you could use the GroupBy and Count method in the else part.

private Dictionary<CardValue, int> CardValueCount
{
    get
    {
        if (Cards.Length < 1 || Cards == null)
        {
            return Enum.GetValues(typeof(CardValue))
                .Cast<CardValue>()
                .ToDictionary(x => x, x => 0);
        }
        else
        {
            return Cards.GroupBy(card => card.Value)
                .ToDictionary(group => group.Key, group => group.Count());
        }
    }
}
Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
1

You can get an array with all the values of the CardValue enumeration, with the static method Enum.GetValues.

// Retrieves an array of the values of the constants in a specified enumeration.
public static Array GetValues (Type enumType);

The array is untyped, so you have to cast each value to CardValue.

Usage example:

Dictionary<CardValue, int> dict = new();
foreach(CardValue x in Enum.GetValues(typeof(CardValue)))
    dict.Add(x, 0);

...or using LINQ:

Dictionary<CardValue, int> dict = Enum.GetValues(typeof(CardValue))
    .Cast<CardValue>()
    .ToDictionary(x => x, x => 0);

Online demo.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104