开发者

Get dictionary key by value

How do I get a Dictionary key by value in C#?

Dictionary<string, string> types = new Dictionary<string, string>()
{
    {"1", "one"},
    {"2", "two"},
    {"3", "three"}
};

I want something like this:

getByValueKey(string value);

getByValueKey("one") must be return "1".

What is the best way do this? Maybe HashTab开发者_StackOverflow社区le or SortedLists?


Values do not necessarily have to be unique, so you have to do a lookup. You can do something like this:

var myKey = types.FirstOrDefault(x => x.Value == "one").Key;

If values are unique and are inserted less frequently than read, then create an inverse dictionary where values are keys and keys are values.


You could do that:

  1. By looping through all the KeyValuePair<TKey, TValue>'s in the dictionary (which will be a sizable performance hit if you have a number of entries in the dictionary)
  2. Use two dictionaries, one for value-to-key mapping and one for key-to-value mapping (which would take up twice as much space in memory).

Use Method 1 if performance is not a consideration, and use Method 2 if memory is not a consideration.

Also, all keys must be unique, but the values are not required to be unique. You may have more than one key with the specified value.


I was in a situation where LINQ binding was not available and had to expand lambda explicitly. It resulted in a simple function:

public static T KeyByValue<T, W>(this Dictionary<T, W> dict, W val)
{
    T key = default;
    foreach (KeyValuePair<T, W> pair in dict)
    {
        if (EqualityComparer<W>.Default.Equals(pair.Value, val))
        {
            key = pair.Key;
            break;
        }
    }
    return key;
}

Call it like follows:

public static void Main()
{
    Dictionary<string, string> dict = new Dictionary<string, string>()
    {
        {"1", "one"},
        {"2", "two"},
        {"3", "three"}
    };

    string key = KeyByValue(dict, "two");
    Console.WriteLine("Key: " + key);
}

It works on .NET 2.0 and in other limited environments.


public static string GetKeyFromValue(string valueVar)
{
    foreach (string keyVar in dictionaryVar.Keys)
    {
        if (dictionaryVar[keyVar] == valueVar)
        {
            return keyVar;
        }
    }
    return null;
}

Other people may have more efficient answers, but I find this personally more intuitive and it works in my case.


I have created a double-lookup class:

/// <summary>
/// dictionary with double key lookup
/// </summary>
/// <typeparam name="T1">primary key</typeparam>
/// <typeparam name="T2">secondary key</typeparam>
/// <typeparam name="TValue">value type</typeparam>
public class cDoubleKeyDictionary<T1, T2, TValue> {
    private struct Key2ValuePair {
        internal T2 key2;
        internal TValue value;
    }
    private Dictionary<T1, Key2ValuePair> d1 = new Dictionary<T1, Key2ValuePair>();
    private Dictionary<T2, T1> d2 = new Dictionary<T2, T1>();

    /// <summary>
    /// add item
    /// not exacly like add, mote like Dictionary[] = overwriting existing values
    /// </summary>
    /// <param name="key1"></param>
    /// <param name="key2"></param>
    public void Add(T1 key1, T2 key2, TValue value) {
        lock (d1) {
            d1[key1] = new Key2ValuePair {
                key2 = key2,
                value = value,
            };
            d2[key2] = key1;
        }
    }

    /// <summary>
    /// get key2 by key1
    /// </summary>
    /// <param name="key1"></param>
    /// <param name="key2"></param>
    /// <returns></returns>
    public bool TryGetValue(T1 key1, out TValue value) {
        if (d1.TryGetValue(key1, out Key2ValuePair kvp)) {
            value = kvp.value;
            return true;
        } else {
            value = default;
            return false;
        }
    }

    /// <summary>
    /// get key1 by key2
    /// </summary>
    /// <param name="key2"></param>
    /// <param name="key1"></param>
    /// <remarks>
    /// 2x O(1) operation
    /// </remarks>
    /// <returns></returns>
    public bool TryGetValue2(T2 key2, out TValue value) {
        if (d2.TryGetValue(key2, out T1 key1)) {
            return TryGetValue(key1, out value);
        } else {
            value = default;
            return false;
        }
    }

    /// <summary>
    /// get key1 by key2
    /// </summary>
    /// <param name="key2"></param>
    /// <param name="key1"></param>
    /// <remarks>
    /// 2x O(1) operation
    /// </remarks>
    /// <returns></returns>
    public bool TryGetKey1(T2 key2, out T1 key1) {
        return d2.TryGetValue(key2, out key1);
    }

    /// <summary>
    /// get key1 by key2
    /// </summary>
    /// <param name="key2"></param>
    /// <param name="key1"></param>
    /// <remarks>
    /// 2x O(1) operation
    /// </remarks>
    /// <returns></returns>
    public bool TryGetKey2(T1 key1, out T2 key2) {
        if (d1.TryGetValue(key1, out Key2ValuePair kvp1)) {
            key2 = kvp1.key2;
            return true;
        } else {
            key2 = default;
            return false;
        }
    }

    /// <summary>
    /// remove item by key 1
    /// </summary>
    /// <param name="key1"></param>
    public void Remove(T1 key1) {
        lock (d1) {
            if (d1.TryGetValue(key1, out Key2ValuePair kvp)) {
                d1.Remove(key1);
                d2.Remove(kvp.key2);
            }
        }
    }

    /// <summary>
    /// remove item by key 2
    /// </summary>
    /// <param name="key2"></param>
    public void Remove2(T2 key2) {
        lock (d1) {
            if (d2.TryGetValue(key2, out T1 key1)) {
                d1.Remove(key1);
                d2.Remove(key2);
            }
        }
    }

    /// <summary>
    /// clear all items
    /// </summary>
    public void Clear() {
        lock (d1) {
            d1.Clear();
            d2.Clear();
        }
    }

    /// <summary>
    /// enumerator on key1, so we can replace Dictionary by cDoubleKeyDictionary
    /// </summary>
    /// <param name="key1"></param>
    /// <returns></returns>
    public TValue this[T1 key1] {
        get => d1[key1].value;
    }

    /// <summary>
    /// enumerator on key1, so we can replace Dictionary by cDoubleKeyDictionary
    /// </summary>
    /// <param name="key1"></param>
    /// <returns></returns>
    public TValue this[T1 key1, T2 key2] {
        set {
            lock (d1) {
                d1[key1] = new Key2ValuePair {
                    key2 = key2,
                    value = value,
                };
                d2[key2] = key1;
            }
        }
    }


A Dictionary<K,V> extension that works. I have been using it for a long time::

public static bool TryGetKey<K, V>(this IDictionary<K, V> instance, V value, out K key)
{
    foreach (var entry in instance)
    {
        if (!entry.Value.Equals(value))
        {
            continue;
        }
        key = entry.Key;
        return true;
    }
    key = default(K);
    return false;
}

And use as :

public static void Main()
{
    Dictionary<string, string> dict = new Dictionary<string, string>()
    {
        {"1", "one"},
        {"2", "two"},
        {"3", "three"}
    };
     
     string value="two"; 
     if (dict.TryGetKey(value, out var returnedKey))
         Console.WriteLine($"Found Key {returnedKey}");
     else
         Console.WriteLine($"No key found for value {value}");
}


Maybe something like this:

foreach (var keyvaluepair in dict)
{
    if(Object.ReferenceEquals(keyvaluepair.Value, searchedObject))
    {
        //dict.Remove(keyvaluepair.Key);
        break;
    }
}


The order of the keys in Keys is unspecified, but it is the same as the associated values in Values (from the C# doc).

So an efficient way (in some situations) to do that for a collection of values looks like:

    /// <summary>
    /// Gets the 1st key matching each value
    /// </summary>
    public static IEnumerable<TKey> GetKeys<TKey,TValue>(this Dictionary<TKey, TValue> dic, IEnumerable<TValue> values) where TKey : notnull
    {
        //The order of the keys in Keys is unspecified, but it is the same as the associated values in Values
        var dicKeys = dic.Keys.ToList();
        var dicValues = dic.Values.ToList();
        foreach (var value in values)
        {
            var i = dicValues.IndexOf(value); //Will return the index of the 1st found value, even when multiple values are present
            //we could test if i==-1 there.
            yield return dicKeys[i];
        }
    }


types.Values.ToList().IndexOf("one");

Values.ToList() converts your dictionary values into a List of objects. IndexOf("one") searches your new List looking for "one" and returns the Index which would match the index of the Key/Value pair in the dictionary.

This method does not care about the dictionary keys, it simply returns the index of the value that you are looking for.

Keep in mind there may be more than one "one" value in your dictionary. And that is the reason there is no "get key" method.


The below code only works if it contains unique value data:

public string getKey(string Value)
{
    if (dictionary.ContainsValue(Value))
    {
        var ListValueData = new List<string>();
        var ListKeyData   = new List<string>();

        var Values = dictionary.Values;
        var Keys = dictionary.Keys;

        foreach (var item in Values)
        {
            ListValueData.Add(item);
        }

        var ValueIndex = ListValueData.IndexOf(Value);
        foreach (var item in Keys)
        {
            ListKeyData.Add(item);
        }

        return  ListKeyData[ValueIndex];
    }
    return string.Empty;
}


I have a very simple way to do this. It worked out perfect for me.

Dictionary<string, string> types = new Dictionary<string, string>();

types.Add("1", "one");
types.Add("2", "two");
types.Add("3", "three");

Console.WriteLine("Please type a key to show its value: ");
string rLine = Console.ReadLine();

if(types.ContainsKey(rLine))
{
    string value_For_Key = types[rLine];
    Console.WriteLine("Value for " + rLine + " is" + value_For_Key);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜