- Dictionary
- Get The Dictionary Keys By Their Value
Get The Dictionary Keys By Their Value Using .NET

Introduction
Normally, C# dictionaries store key and value pairs and to access the values you need to pass in the key. If you want to access the keys by searching for a set of values or a particular value to get the key, then you'll need to loop through the values. These two scenarios are to consider when making this kind of search. First, are the values unique? If not then we need to loop through the values in some fashion. So I'll go through each of these methods one by one.
When The Dictionary Values Are Unique Then Reverse The Dictionary
If the values of the dictionary are unique then the dictionary can be reversed by putting the values as keys and then the keys as the values. We can create a new dictionary or have two dictionaries. One dictionary where it's regular keys and values and then another with the keys and values reversed. Consider the following example.
If I have a dictionary that holds the months of the year as a string as a key then the values would be the corresponding number of the month.
Reverse Dictionary Method Example Code
Dictionary<string, int> monthlyDictionary = new Dictionary<string, int>() { { "Jan", 1 }, { "Feb", 2 }, { "Mar", 3 }, { "April", 4 }, { "May", 5 }, { "Jun", 6 }, { "July", 7 }, { "Aug", 8 }, { "Sept", 9 }, { "Oct", 10 }, { "Nov", 11 }, { "Dec", 12 } };//initialize dictionary
foreach(KeyValuePair<string,int> monthly in monthlyDictionary)//loop through key value pairs
{
Console.WriteLine($"key:{monthly.Key}, value:{monthly.Value}");//print key and value pairs to screen
}
Code Output
key:Jan, value:1
key:Feb, value:2
key:Mar, value:3
key:April, value:4
key:May, value:5
key:Jun, value:6
key:July, value:7
key:Aug, value:8
key:Sept, value:9
key:Oct, value:10
key:Nov, value:11
key:Dec, value:12
If this is the baseline that we are working with and we want to find the keys based on the selected values then we just need to reverse the dictionary. We can only do this because the values are also unique. For this example, that looks like the following.
Dictionary<int, string> monthlyDictionary = new Dictionary<int, string>() { { 1, "Jan" }, { 2, "Feb" }, { 3, "Mar" }, { 4, "April" }, { 5, "May" }, { 6, "Jun" }, { 7, "July" }, { 8, "Aug" }, { 9, "Sept" }, { 10, "Oct" }, { 11, "Nov" }, { 12, "Dec" } };//initialize dictionary
//If want month 4 then we can access it by using the accessor with the number 4
Console.WriteLine($"key:4, value:{monthlyDictionary[4]}");//print key and value pairs to screen
Code Output
key:4, value:April
This reverse of the dictionary keys and values is best if both are unique if not then we need to loop through the values. So let's go through the first option to loop through the values.
Reverse Dictionary Method Speed Test
Next, I want to test the speed of this method. I will do the following. Run 10 tests and average the speed between the tests. Each test will run a method 1000 times. Each method will have 1 million objects of data. Since the keys and values are reversed. For this test, I will generate a dictionary with 1 million objects then at the end add the one entry I plan to look for to show the look-up speed of the item I'm looking for. Let's examine the test code below.
using System.Diagnostics;
int numberOfTests = 10;//Number of tests
int numberOfFunctionCalls = 1000;//Number of function calls made per test
int numberOfObjectsToCreate = 1000000;//1 million test objects
string testName = "Reverse Dictionary Method";//Test name to print to average
string valueToLookFor = "Jan";
string TestMethod(Dictionary<string, string> dictionary)
{
string date = dictionary[valueToLookFor];//Once the Reverse Dictionary is set up and the keys and values are switched then we only need access to the value.
return date;
}
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
testSpeedList.Add(StartTest());
}
Console.WriteLine($"{testName} Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
double StartTest()
{
Stopwatch stopwatch = new Stopwatch();
Dictionary<string, string> testData = GetDictionaryData();//Get intial random generated data
for (int i = 0; i < numberOfFunctionCalls; i++)
{
stopwatch.Start();//Start the Stopwatch timer
TestMethod(testData);//
stopwatch.Stop();//Stop the Stopwatch timer
}
stopwatch.Stop();//Stop the Stopwatch timer
Console.WriteLine($"Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
return stopwatch.Elapsed.TotalMilliseconds;
}
Supporting Code
Dictionary<string, string> GetDictionaryData()
{
Dictionary<string, string> testData = new Dictionary<string, string>();
Dictionary<int, string> monthlyDictionary = new Dictionary<int, string>() { { 1, "Jan" }, { 2, "Feb" }, { 3, "Mar" }, { 4, "April" }, { 5, "May" }, { 6, "Jun" }, { 7, "July" }, { 8, "Aug" }, { 9, "Sept" }, { 10, "Oct" }, { 11, "Nov" }, { 12, "Dec" } };//initialize dictionary
while (numberOfObjectsToCreate > testData.Count)
{
DateTime date = GetDateTime();
string dateString = date.ToShortDateString();
string month = monthlyDictionary[date.Month];
if (!testData.ContainsKey(dateString))
{
testData[dateString] = month;
}
}
testData.Add("Jan", "1/20/2020");
return testData;
}
int GetRandomInt(int minNumber, int maxNumber)
{
Random random = new Random();//Create Random class
int randomInt = random.Next(minNumber, maxNumber);//Get a random number between 1 and the maxnumber
return randomInt;
}
DateTime GetDateTime()
{
DateTime dateTime = new DateTime(GetRandomInt(1, 4000), GetRandomInt(1, 12), GetRandomInt(1, 29));
return dateTime;
}
Code Output
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Reverse Dictionary Method Average speed:0ms, In 10 tests
This dictionary method is extremely fast. It is less than a millisecond. This is the go-to method to solve this issue, but now we'll look at methods to deal with values that are duplicated.
LINQ Value Loop Method
If the use case is that the values are not unique then we need to loop through all the values and find the ones we are looking through. We can write a LINQ function to loop through all the values of the dictionary and return a list of keys that match. In this example, there's a dictionary with a date as the key and then the month as the value. Multiple dates map the same month as the value. This code will find the dates that correspond to the Jan dates. Examine the code below.
Dictionary<string, string> dateMonthDictionary = new Dictionary<string, string>() { { "1/20/2023", "Jan" }, { "2/04/2022", "Feb" }, { "1/08/2022", "Jan" }, { "4/13/2018", "April" }, { "3/28/2017", "Mar" }, { "4/15/2020", "April" }, { "12/24/2017", "Dec" }, { "10/18/2000", "Oct" }, { "12/20/2000", "Dec" } };
string valueToLookFor = "Jan";
List<string> keys = dateMonthDictionary.Where(x => x.Value == valueToLookFor).Select(y => y.Key).ToList();
foreach (string key in keys)
{
Console.WriteLine($"key:{key}, value:{valueToLookFor}");//print key pairs to screen
}
Code Output
key:1/20/2023, value:Jan
key:1/08/2022, value:Jan
Two dates occurred in Jan and they are returned by this function.
LINQ Value Loop Speed Test
This is the same test used before. There will be 10 tests and each with 1000 loops of the method. The method will have data with 1 million objects. Let's see how LINQ can process the request with 1 million objects
using System.Diagnostics;
int numberOfTests = 10;//Number of tests
int numberOfFunctionCalls = 1000;//Number of function calls made per test
int numberOfObjectsToCreate = 1000000;//1 million test objects
string testName = "LINQ Value Loop Method";//Test name to print to average
string valueToLookFor = "Jan";
List<string> TestMethod(Dictionary<string, string> dictionary)
{
List<string> keys = dictionary.Where(x => x.Value == valueToLookFor).Select(y => y.Key).ToList();//loop through each key-value pair and check if the value is the match we're looking for then add each key to a list
return keys;
}
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
testSpeedList.Add(StartTest());
}
Console.WriteLine($"{testName} Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
Supporting Code
double StartTest()
{
Stopwatch stopwatch = new Stopwatch();
Dictionary<string, string> testData = GetDictionaryData();//Get intial random generated data
for (int i = 0; i < numberOfFunctionCalls; i++)
{
stopwatch.Start();//Start the Stopwatch timer
TestMethod(testData);//
stopwatch.Stop();//Stop the Stopwatch timer
}
stopwatch.Stop();//Stop the Stopwatch timer
Console.WriteLine($"Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
return stopwatch.Elapsed.TotalMilliseconds;
}
Dictionary<string, string> GetDictionaryData()
{
Dictionary<string, string> testData = new Dictionary<string, string>();
Dictionary<int, string> monthlyDictionary = new Dictionary<int, string>() { { 1, "Jan" }, { 2, "Feb" }, { 3, "Mar" }, { 4, "April" }, { 5, "May" }, { 6, "Jun" }, { 7, "July" }, { 8, "Aug" }, { 9, "Sept" }, { 10, "Oct" }, { 11, "Nov" }, { 12, "Dec" } };//initialize dictionary
while (numberOfObjectsToCreate > testData.Count)
{
DateTime date = GetDateTime();
string dateString = date.ToShortDateString();
string month = monthlyDictionary[date.Month];
if (!testData.ContainsKey(dateString))
{
testData[dateString] = month;
}
}
return testData;
}
int GetRandomInt(int minNumber, int maxNumber)
{
Random random = new Random();//Create Random class
int randomInt = random.Next(minNumber, maxNumber);//Get a random number between 1 and the maxnumber
return randomInt;
}
DateTime GetDateTime()
{
DateTime dateTime = new DateTime(GetRandomInt(1, 4000), GetRandomInt(1, 12), GetRandomInt(1, 29));
return dateTime;
}
Code Output
Function calls:1000, In 0m 20s 864ms
Function calls:1000, In 0m 20s 707ms
Function calls:1000, In 0m 20s 681ms
Function calls:1000, In 0m 20s 599ms
Function calls:1000, In 0m 20s 951ms
Function calls:1000, In 0m 20s 696ms
Function calls:1000, In 0m 20s 517ms
Function calls:1000, In 0m 20s 335ms
Function calls:1000, In 0m 20s 575ms
Function calls:1000, In 0m 20s 543ms
LINQ Value Loop Method Average speed:20647ms, In 10 tests
This LINQ method is slow. This is because all the values need to be looped so that it can find all the matches.
Dictionary With List Method
Another way we can approach this is to have a dictionary that will allow us to store the multiple values in a list of the keys that end up duplicated. This will allow us the speed of the dictionary and also the storage of a list of the values. The values will be stored as keys then each of the keys will be stored in a list that has the same value. Let's look at the code to see this approach.
Dictionary<string, List<string>> dateMonthDictionary = new Dictionary<string, List<string>>();
dateMonthDictionary["Jan"] = new List<string>();
dateMonthDictionary["Jan"].Add("1/20/2023");//Add to list for this key
dateMonthDictionary["Jan"].Add("1/08/2022");//Add to list for this key
dateMonthDictionary["Feb"] = new List<string>();
dateMonthDictionary["Feb"].Add("2/04/2022");//Add to list for this key
dateMonthDictionary["April"] = new List<string>();
dateMonthDictionary["April"].Add("4/13/2018");//Add to list for this key
dateMonthDictionary["April"].Add("4/15/2020");//Add to list for this key
dateMonthDictionary["Mar"] = new List<string>();
dateMonthDictionary["Mar"].Add("3/28/2017");//Add to list for this key
dateMonthDictionary["Dec"] = new List<string>();
dateMonthDictionary["Dec"].Add("12/24/2017");//Add to list for this key
dateMonthDictionary["Dec"].Add("12/20/2000");//Add to list for this key
dateMonthDictionary["Oct"] = new List<string>();
dateMonthDictionary["Oct"].Add("10/18/2000");//Add to list for this key
string valueToLookFor = "Jan";
List<string> keys = new List<string>();
dateMonthDictionary.TryGetValue(valueToLookFor, out keys);//Get list of keys have been placed in the list
foreach (string key in keys)
{
Console.WriteLine($"key:{key}, value:{valueToLookFor}");//print key pairs to screen
}
Code Output
key:1/20/2023, value:Jan
key:1/08/2022, value:Jan
Dictionary With List Method Speed Test
We'll perform the same test as the other two methods. With 10 tests and each test will loop through the method 1000 times and the method will have 1 million data points.
using System.Diagnostics;
int numberOfTests = 10;//Number of tests
int numberOfFunctionCalls = 1000;//Number of function calls made per test
int numberOfObjectsToCreate = 1000000;//1 million test objects
string testName = "Dictionary With List Method";//Test name to print to average
string valueToLookFor = "Jan";
List<string> TestMethod(Dictionary<string, List< string>> dictionary)
{
dictionary.TryGetValue(valueToLookFor, out List<string> keys);
return keys;
}
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
testSpeedList.Add(StartTest());
}
Console.WriteLine($"{testName} Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
Supporting Code
double StartTest()
{
Stopwatch stopwatch = new Stopwatch();
Dictionary<string, List<string>> testData = GetDictionaryData();//Get intial random generated data
for (int i = 0; i < numberOfFunctionCalls; i++)
{
stopwatch.Start();//Start the Stopwatch timer
TestMethod(testData);//
stopwatch.Stop();//Stop the Stopwatch timer
}
stopwatch.Stop();//Stop the Stopwatch timer
Console.WriteLine($"Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
return stopwatch.Elapsed.TotalMilliseconds;
}
Dictionary<string, List<string>> GetDictionaryData()
{
int count = 0;
Dictionary<string, List<string>> testData = new Dictionary<string, List<string>>();
Dictionary<int, string> monthlyDictionary = new Dictionary<int, string>() { { 1, "Jan" }, { 2, "Feb" }, { 3, "Mar" }, { 4, "April" }, { 5, "May" }, { 6, "Jun" }, { 7, "July" }, { 8, "Aug" }, { 9, "Sept" }, { 10, "Oct" }, { 11, "Nov" }, { 12, "Dec" } };//initialize dictionary
while (numberOfObjectsToCreate > count)
{
DateTime date = GetDateTime();
string dateString = date.ToShortDateString();
string month = monthlyDictionary[date.Month];
if (!testData.ContainsKey(month))
{
testData[month] = new List<string>();
testData[month].Add(dateString);
}
else
{
testData[month].Add(dateString);
}
count++;
}
return testData;
}
int GetRandomInt(int minNumber, int maxNumber)
{
Random random = new Random();//Create Random class
int randomInt = random.Next(minNumber, maxNumber);//Get a random number between 1 and the maxnumber
return randomInt;
}
DateTime GetDateTime()
{
DateTime dateTime = new DateTime(GetRandomInt(1, 4000), GetRandomInt(1, 12), GetRandomInt(1, 29));
return dateTime;
}
Code Output
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Function calls:1000, In 0m 0s 0ms
Dictionary With List Method Average speed:0ms, In 10 tests
This method returns extremely fast and we can return multiple values almost instantly.
Conclusion
Overall Rank | Method | Speed | Unique Values Required |
---|---|---|---|
1 | Dictionary With List | 0ms | No |
2 | Reverse Dictionary | 0ms | Yes |
3 | LINQ Value Loop | 20647ms | No |
The best way to get keys by their values is to use a dictionary and list combo method because it still uses the incredible speed of the dictionary and the duplicate entries can be stored in a list. This method doesn't require that the values be unique. This is about properly setting the dictionary so that you can the values you need. The next best method is the reverse dictionary method but putting the values as the keys and the keys as values, but you'll need the values that you'll be putting into the keys. They need to be unique for this to work. But it is incredibly fast in the search for the values you want. The next method of using a LINQ expression is slow and this is because LINQ has to loop through all the values to get all the associated keys.
Do you have other methods to solve this issue? Let me know in the comments below.