2

I have a code:

var status = ...
var StatusMapping = new Dictionary<AnotherStatus, IList<Status>>
{
    {
        AnotherStatus,
        new List<Status>
        {
            Status1,
            Status2
        }
    }
}

foreach (var keyValuePair in StatusMapping)
{
    if (keyValuePair.Value.Contains(status))
    {
        return keyValuePair.Key;
    }
}

throw Exception(); 

I'm new to C#, switched from Java. In java it is easily done like this:

return StatusMapping
    .entrySet()
    .stream()
    .filter(e -> e.getValue().contains(status))
    .map(Map.Entry::getKey)
    .findFirst()
    .orElseThrow(() -> new Exception());

Is there a way to do it with LINQ?

  • To get a value from a dictionary just use StatusMapping[key] – jdweng Mar 29 '19 at 15:20
  • @jdweng: That's not what the OP is trying to do. – Jon Skeet Mar 29 '19 at 15:24
  • Possible duplicate of [get dictionary key by value](https://stackoverflow.com/q/2444033/1260204) or [How to get item from dictionary by value of property](https://stackoverflow.com/q/8617456/1260204) – Igor Mar 29 '19 at 15:27

1 Answers1

10

Firstly, if you're doing this regularly, you might want to consider an alternative data structure. Dictionaries aren't really intended for frequent "lookup based on some aspect of the value".

Oh it's rather simpler in C# :)

var key = StatusMapping.First(x => x.Value.Contains(status)).Key;

First() will throw an exception if there aren't any matches.

If you wanted to end up with a default value instead, you could use:

var key = StatusMapping.FirstOrDefault(x => x.Value.Contains(status)).Key;

This will result in key being the default value for AnotherStatus (or whatever the key type is).

Note that this only works exactly like this because KeyValuePair<,> is a value type, so the default value is non-null, with a default key. If you had a sequence of reference types, you would need something like:

var property = sequence.FirstOrDefault(whatever)?.Property;

... where ?. is the null conditional operator.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    KeyValuePair is a value type was new to me. if `var key = StatusMapping.FirstOrDefault(x => x.Value.Contains(status)).Key;` is called with a status that is not in the Value List for any key in the dictionary, the key variable will have the default value of the Status Enum. Was this behavior intentional? (would have expected an exception) – Matt.G Mar 29 '19 at 15:42
  • @Matt.G: It'll have the default value of whatever the key type is, not of `Status`. Yes, that's intentional - I've clarified it as "If you wanted to end up with a default value instead". But `First()` *will* throw an exception. So you can make it behave whichever way you want. – Jon Skeet Mar 29 '19 at 15:47
  • Thanks for the explanation. I think I am more interested in finding out the reasoning behind the design decision to make KeyValuePair a struct (value type), rather than a class (ref type) (a reference link would be sufficient). also, it was typo from my end, I meant default value of AnotherStatus (which is the key). – Matt.G Mar 29 '19 at 15:53
  • 1
    @Matt.G: I suspect it was mostly for efficiency. You typically *don't* to create a whole extra object per element while iterating over a dictionary (or permanently when storing the elements). – Jon Skeet Mar 29 '19 at 15:55
  • What data structure would you suggest for such case? –  Mar 29 '19 at 15:56
  • 1
    @KirillBazarov: We don't know enough about the use case to say. You might want to keep two dictionaries, one each way, for example. – Jon Skeet Mar 29 '19 at 16:06