Why is Dictionary.First so slow?
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
In software development, especially when it comes to optimizing code for performance, developers often scrutinize seemingly simple methods that might carry hidden complexities. One such method is `Dictionary.First()` in C#. While dictionaries are generally known for fast lookup times due to their hash-based structure, using `First()` on a dictionary can be surprisingly slow. This article dives into why this might be the case, offering technical explanations and examples.
How Dictionary.First() Works
In C#, dictionaries are implemented using hashtables, providing near O(1) average-time complexity for lookup operations due to their dispersion of keys. However, `Dictionary.First()` is part of LINQ (Language Integrated Query), which operates differently from typical dictionary operations.
LINQ and Deferred Execution
LINQ is powerful mainly because of its ability to run queries on collections in a declarative manner. One key feature of LINQ is deferred execution, meaning that a query is not executed when it's defined but when its results are iterated over. This is crucial for understanding why `First()` might be slow when used on a dictionary.
`First()` in LINQ
When calling `First()` on a dictionary, LINQ doesn't have direct access to the internal structure of the dictionary. Instead, it treats the dictionary as an `IEnumerable<KeyValuePair<TKey, TValue>>`. LINQ must therefore enumerate over the collection to fetch the first element, which involves:
- Creating an Enumerator: The dictionary must construct an enumerator implementing the `IEnumerator<KeyValuePair<TKey, TValue>>` interface.
- Enumeration: The enumerator traverses entries in the dictionary.
While this might seem trivial, when applied to a substantial dictionary, it adds overhead such as:
- Boxing/Unboxing: For value types `TKey` and `TValue`, converting between types during enumeration can lead to performance degradation.
- Iterator Allocation: An iterator is created and disposed of, adding to memory overhead.
- Abstraction Layer: LINQ abstracts away the underlying implementation for ease of use, but might have efficiency trade-offs.
Example of Dictionary.First()
Consider the following example in C#:
Related reading
- Why is faster than list?
- Why is Git not considered a block chain?
- Why is HashSetPoint so much slower than HashSetstring?
- Why is Insertion sort better than Quick sort for small list of elements?
- Why is docker build taking so long to run?
- Why is Facebook Javascript SDK loaded asynchronously?
- Why is HttpClient BaseAddress not working?
- Why is it even possible to change a private member, or run a private method in C using reflection?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.