-1

I created a System.Collections.Generic.Dictionary d and populated it with int-string key-value pairs.

Given a key k, I can obtain its value by calling d[k].

However, how can I achieve the converse? That is, given a value v, how can I obtain its key?

wjmolina
  • 2,625
  • 2
  • 26
  • 35
  • 3
    You cannot reliably do that because a dictionary's values are non-unique. Whereas its keys have to be unique, its values do not, thus you must iterate through its keys and values and return an array of keys that match the value. – Pharap Jul 08 '13 at 15:42
  • this is a frequent duplicate question; see http://stackoverflow.com/questions/2444033/get-dictionary-key-by-value – jltrem Jul 08 '13 at 15:42
  • As Pharap said, your code will need to handle an array of indices if there is more than one duplicate value. If you only care about the first index found, use .FirstOrDefault(). – MadHenchbot Jul 08 '13 at 15:47

9 Answers9

5

One option is to iterate through all of the pairs to find the one(s) with the value you're looking for, and then to get the keys from those pair. If you're willing to search through the whole dictionary and not have fast lookup speeds, this would be appropriate.

If this is something you're doing a lot, then it's an indication that your dictionary is "backwards" and it should either be reversed, or that you should have do dictionaries, one for a "forwards" lookup and one for a "backwards" lookup. Doing this would double the memory footprint of your program as well as a noticable increase in complexity (you need to ensure the two collections stay in sync). You can find some existing solutions of a "bi-directional dictionary" (i.e. this one by Jon Skeet) which would be encapsulating these two dictionaries in one class (so that you don't need to do the work to ensure they stay in sync; operations will mutate both dictionaries). If this is something you do a lot, consider using or making such a type.

Community
  • 1
  • 1
Servy
  • 202,030
  • 26
  • 332
  • 449
2

You will have more than one key with specific value, so just use LINQ you can get the result:

 var keys = dic.Where(p => p.Value == v)
               .Select(p => p.Key);

To improve performance of accessing, you can create an inverse dictionary:

 var inverseDic = dic.GroupBy(p => p.Value)
                     .ToDictionary(g => g.Key, 
                                   g => g.Select(p => p.Key));

So, to get the keys:

var keys = inverseDic[v];
cuongle
  • 74,024
  • 28
  • 151
  • 206
2
public int[] GetKeys(string value)
{
List<int> list = new List<int>();
for(int i = 0;i<dict.Values.Count;i++)
{
if(dict.Values[i] == value){list.Add(dict.Keys[i]);}
}
return list.ToArray();
}
Pharap
  • 3,826
  • 5
  • 37
  • 51
0

It should be enough to do something like:

var dic = new Dictionary<int, string>() {....}
var foundKey = dic.FirstOrDefault(kvp=>kvp.Value == YOUR_SEARCH_VALUE_HERE).Key;
Tigran
  • 61,654
  • 8
  • 86
  • 123
0
var key = dictionary.FirstOrDefault(d => d.Value == value).Key;
Jonesopolis
  • 25,034
  • 12
  • 68
  • 112
0

You can do this:

var dict = new Dictionary<TKey, TValue>() ...
TValue myValue = ...
var myKey = dict.First(pair => pair.Value == myValue).Key;

This might fail if the value is not found in the dictionary. To be a bit safer you can do this:

var myKey = dict.FirstOrDefault(pair => pair.Value == myValue).Key;

Here myKey will take the default value of type TKey (null for strings or other classes, 0 for integers, etc.), so depending on your exact situation you may need to take some care in how you handle this case.

Also, it's important to realize that you could have many keys with the same value. To select all of the keys use this:

var myKeys = dict.Where(pair => pair.Value == myValue).Select(pair => pair.Key);

Or in query syntax:

var myKeys =
    from pair in dict
    where pair.Value == myValue
    select pair.Key;
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
0
var key = dictionary.FirstOrDefault(d => d.Value == value).Key;
Sam Leach
  • 12,746
  • 9
  • 45
  • 73
  • This won't compile. You have a sequence of pairs, you can't get the key from a sequence. You need to either take the first, or select out the key from them all (if you want them all). – Servy Jul 08 '13 at 15:48
  • Yep, true. I meant first. Edited. – Sam Leach Jul 08 '13 at 15:53
0

Yes you can use d[k] but dont forget to use d.ContainsKey(k) or you get exception. And you can use var key = d.FirstOrDefault(x => x.Value == value).Key;

Suhan
  • 1,434
  • 2
  • 13
  • 28
0

If this is something you'll be doing often, or if you want to ensure that each value is only added once, you should make a custom data type with two dictionaries inside it: one <int,string> and the other <string,int>. You could interface with it like a normal dictionary of either type. The class declaration might look like this:

public class DoubleDictionary<T1, T2> : IDictionary<T1, T2>, IDictionary<T2, T1>

Jon Skeet created a full implementation of such a dictionary, with and without multiple values per key.

Community
  • 1
  • 1
Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • Note that it depends on whether the "values" are unique as well. If they aren't, then it's a `IDictionary, IDictionary>` because there could be multilpe `T1` types for each `T2` in the collection. – Servy Jul 08 '13 at 15:46