Dictionary
C#
Programming
Key-Value Pairs
Data Structures

Getting multiple keys of specified value of a generic Dictionary?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A Dictionary<TKey, TValue> is optimized for looking up a value by key, not for looking up all keys that share a value. So if you want every key whose value equals a target value, the direct answer is to scan the dictionary and collect matches.

The Straightforward O(n) Solution

If this is a one-off query, just iterate through the entries. In C#, LINQ makes that readable.

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5class Program
6{
7    static void Main()
8    {
9        var scores = new Dictionary<string, int>
10        {
11            ["alice"] = 10,
12            ["bob"] = 20,
13            ["carol"] = 10,
14            ["dave"] = 30
15        };
16
17        int target = 10;
18        List<string> keys = scores
19            .Where(pair => pair.Value == target)
20            .Select(pair => pair.Key)
21            .ToList();
22
23        Console.WriteLine(string.Join(", ", keys));
24    }
25}

This is the right default if you only need the query occasionally. The runtime is O(n) because every entry must be checked.

Why There Is No Faster Direct Lookup

A dictionary stores hash information for keys, not for values. That means it has no index from value to matching keys unless you build one yourself.

So a statement like “get all keys for this value” is not a native constant-time dictionary operation. It is effectively a filter over the full collection.

That is not a flaw. It is just the tradeoff of the data structure.

If You Need This Query Repeatedly

If the program often asks for keys by value, scanning every time becomes wasteful. In that case, build a reverse lookup structure.

One clean option is ILookup<TValue, TKey>.

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5class Program
6{
7    static void Main()
8    {
9        var scores = new Dictionary<string, int>
10        {
11            ["alice"] = 10,
12            ["bob"] = 20,
13            ["carol"] = 10,
14            ["dave"] = 30
15        };
16
17        ILookup<int, string> reverse = scores.ToLookup(pair => pair.Value, pair => pair.Key);
18
19        foreach (string key in reverse[10])
20        {
21            Console.WriteLine(key);
22        }
23    }
24}

This front-loads the cost of building the reverse view so repeated lookups become simpler and faster.

A Mutable Reverse Index

If the dictionary changes often and you still need fast value-to-keys lookups, you may need two synchronized structures:

  • the main Dictionary<TKey, TValue>
  • a reverse Dictionary<TValue, HashSet<TKey>>

That design supports fast access in both directions, but it increases update complexity because every insert, delete, or value change must update both structures consistently.

The right choice depends on workload:

  • occasional reverse query: scan once
  • many reverse queries on mostly static data: build a lookup
  • many reverse queries on frequently updated data: maintain a reverse index

Equality Matters

Value comparison depends on the equality semantics of TValue. For built-in value types such as int or DateTime, the default comparison is usually what you want. For custom classes, you may need to override equality or provide a comparer if “same value” is supposed to mean more than reference equality.

If equality is wrong, the lookup logic appears broken even though the filtering code is fine.

A Non-LINQ Version

Some teams prefer an explicit loop because it avoids extra allocations from intermediate query stages and is easier to debug.

csharp
1List<string> FindKeysByValue<TKey, TValue>(Dictionary<TKey, TValue> dict, TValue target)
2{
3    var result = new List<string>();
4    foreach (var pair in dict)
5    {
6        if (EqualityComparer<TValue>.Default.Equals(pair.Value, target))
7        {
8            result.Add(pair.Key?.ToString() ?? string.Empty);
9        }
10    }
11    return result;
12}

The key idea is unchanged: inspect every entry.

Common Pitfalls

A common mistake is expecting the dictionary itself to support reverse lookup efficiently. It does not unless you build that structure.

Another mistake is using reference types as values and forgetting that default equality may compare object identity instead of logical content.

A third issue is overengineering the solution. If the query runs once, a plain scan is usually the best option.

Summary

  • 'Dictionary<TKey, TValue> is optimized for key-to-value access, not reverse lookup.'
  • To get all keys for a value, scan the entries and collect matches.
  • The direct one-off solution is O(n) and usually correct.
  • If reverse lookups are frequent, build a lookup or a dedicated reverse index.
  • Make sure value equality matches your intended notion of “same value”.

Course illustration
Course illustration

All Rights Reserved.