Get dictionary key by value

C#Dictionary

C# Problem Overview


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 HashTable or SortedLists?

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

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.

Solution 3 - C#

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.

Solution 4 - C#

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.

Solution 5 - C#

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;
			}
		}
	}

Solution 6 - C#

Maybe something like this:

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

Solution 7 - C#

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.

Solution 8 - C#

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;
}

Solution 9 - C#

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);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlovijiView Question on Stackoverflow
Solution 1 - C#KimiView Answer on Stackoverflow
Solution 2 - C#Zach JohnsonView Answer on Stackoverflow
Solution 3 - C#Boris ZinchenkoView Answer on Stackoverflow
Solution 4 - C#Josh McGeeView Answer on Stackoverflow
Solution 5 - C#PTKView Answer on Stackoverflow
Solution 6 - C#Shimon DoodkinView Answer on Stackoverflow
Solution 7 - C#EricMView Answer on Stackoverflow
Solution 8 - C#Pradeep Kumar DasView Answer on Stackoverflow
Solution 9 - C#Dushyant PatelView Answer on Stackoverflow