Search code examples
c#dictionarylambdawhere-clauseanonymous

C# Dictionary search predicate as method argument


I am trying to create a function whereby I can pass in a functor/predicate that can slot into a dictionary's 'Where' method.

(cardPool is the dictionary of type 'cardStats') Pseudo of what I'd like to do:

void CardStats findCard(Predicate<CardStats> pred)
{
    return cardPool.Where(pred);
}

This code obviously wont work but is simply a rough example of the functionality I am looking for. I have had no problems setting this up for lists, but for a Dictionary, its really got me stumped.

Any help would be great, thanks!

Edit: Ahh sorry I should have mentioned more: Cardstats is the value, the key is of type int. I'd like to sift through the values (cardStats) and test their properties such as ID(int) or name(string).


Solution

  • Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>>, so its Where extension method takes a predicate of type Func<KeyValuePair<TKey, TValue>, bool>.

    You could implement your method like this:

    void CardStats findCard(Func<int, CardStats, bool> pred)
    {
        return cardPool.Where(kv => pred(kv.Key, kv.Value))
                       .Select(kv => kv.Value)
                       .FirstOrDefault();
    }
    

    And use it like this:

    CardStats stats = myCards.findCard((id, stats) => id == 7);
    

    or

    CardStats stats = myCards.findCard((id, stats) => stats.Name == "Ace of Clubs");
    

    Note that using Where on a dictionary doesn't take advantage of the dictionary's quick lookup features and basically treats it as a linear collection of key-value pairs.


    One more comment: I would suggest providing a method that returns an IEnumerable of found cards if there are several. Or you could provide one that does that, and one that just returns the first match:

    void IEnumerable<CardStats> findCards(Func<int, CardStats, bool> pred)
    {
        return cardPool.Where(kv => pred(kv.Key, kv.Value))
                       .Select(kv => kv.Value);
    }
    
    void CardStats findCard(Func<int, CardStats, bool> pred)
    {
        return findCards(pred).FirstOrDefault();
    }