2

I have defined Enumand Dictionary as below. Now in Dictionary, I want to get Key from Value using Linq

enum Devices
    {
        Fan,
        Bulb,
        Mobile,
        Television
    };

Dictionary<int, Devices> dctDevices = new Dictionary<int, Devices>()
{
    {1, Devices.Fan},
    {2, Devices.Bulb},
    {3, Devices.Mobile},
    {4, Devices.Television}
};

I want result like below. I need concrete method named below.

int key = GetKeyFromValue(Devices.Bulb);

Please suggest me the best way to perform this. Thanks in advance

Prem
  • 301
  • 2
  • 10
  • Sorry, its counter 1, 2, 3, 4 – Prem Aug 29 '18 at 11:29
  • 2
    maybe a question, why not `Dictionary` instead? :P – Vladi Pavelka Aug 29 '18 at 11:30
  • I was going to say the same thing as @VladiPavelka, why not use devices as key? – Selman Genç Aug 29 '18 at 11:30
  • 2
    Btw. if you don't specify otherwise, an `enum` value basically already is an `int` value (starting with `0`). I don't know what the key should actually represent, but maybe your use case is simply: `int key = (int)value + 1;` – Corak Aug 29 '18 at 11:31
  • For device at first, I can understand but it's actual requirement. I can,t put Dictionary at first. Thank for suggestion. – Prem Aug 29 '18 at 11:32
  • The accepted answer in the duplicate question doesn't handle the case that the value wasn't found. It works accidentially for reference type keys(because a dictionary key cannot be null)) but not for value types like here, especially if `0` was a valid key in the dictionary. – Tim Schmelter Aug 29 '18 at 12:33

2 Answers2

1

The method could look like:

int GetKeyFromValue(Devices device)
{
    return dctDevices.Keys
        .Where(k => dctDevices[k] == device)
        .DefaultIfEmpty( -1 ) // or whatever "not found"-value
        .First();
}

or a generic extension method for any type:

public static TKey GetKeyByBalue<TKey, TValue>(this IDictionary<TKey, TValue> dict, TValue value, TKey notFoundKey, IEqualityComparer<TValue> comparer = null)
{
    if (comparer == null)
        comparer = EqualityComparer<TValue>.Default;
    return dict.Keys.Where(k => comparer.Equals(dict[k], value)).DefaultIfEmpty(notFoundKey).First();
}

Note that you should use another dictionary if you want to lookup that value often:

Dictionary<Devices, int> DeviceKeys = new Dictionary<Devices, int>()
{
    {Devices.Fan, 1}, // ...
};

Then the code becomes more efficient:

int key = DeviceKeys[Devices.Bulb];

Or create a custom class Device which encapsulates the ID and the Devices (and other things):

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • The "backwards" dictionary can simply be created by `var backwards = dctDevices.ToDictionary(x => x.Value, x => x.Key);` in this case, since OP seems to expect a strict 1:1 relation. Otherwise, a similar `ToLookup` might be needed. – Corak Aug 29 '18 at 11:50
  • @Corak: the point was that he should not need to create it always, that's why i haven't shown the creation but initialized the dictionary manually once. But yes, you could initialize it also in that way. – Tim Schmelter Aug 29 '18 at 11:52
  • Thanks, first answer helped me. It returns -1 if not exists. – Prem Aug 29 '18 at 11:55
-1

You can do it like below:

dctDevices.AsEnumerable().Where(p => p.Value == Devices.Bulb).FirstOrDefault().Key;
Pelin
  • 936
  • 5
  • 12