How to iterate a Dictionary in C# ?
When working with key–value pairs in C#, the Dictionary<TKey, TValue> is one of the most powerful and frequently used generic collections. However, a common question developers face is
How do I iterate through a Dictionary in C# efficiently and correctly?
In this article, we’ll explore all the practical and advanced ways to iterate through a Dictionary, understand what happens internally, learn about performance considerations and see real-world examples you can directly use in production code.
What is a Dictionary in C#?
A Dictionary in C# (defined in the System.Collections.Generic namespace) stores key–value pairs where each key must be unique and values can be duplicated. It provides O(1) average-time lookups, insertions and deletions thanks to its internal hash table implementation. Click here to learn Dictionary in depth
Internal Working of Dictionary
Internally, Dictionary<TKey, TValue> uses
- Buckets : an array storing indices of entries.
- Entries : an array of structures containing {hashCode, key, value, next}
How to Iterate a Dictionary in C#?
In C# , Dictionary is unordered Data structure,which means that you cann't expect that the return values of a Dictionary will be in same order every time. So when you loop/iterate it more time it can print values in different order and order of values unpredictable.
There are several ways to iterate through a dictionary in C#, each suitable for different use cases.
1. Using foreach Loop : The Most Common and Readable Way
The foreach loop is the most straightforward and commonly used approach to iterate through all the key–value pairs in a dictionary. It’s clean, safe and works for all data types.
using System.IO;
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Dictionary < string,string> dict = new Dictionary<string,string> {
{"language","C#"},
{"topic","Dictionary"},
{"label","Beginner"}
};
foreach(KeyValuePair<string,string> kvp in dict) {
Console.WriteLine( $"Key : {kvp.Key} Value : {kvp.Value}");
}
}
}Key : language Value : C# Key : topic Value : Dictionary Key : label Value : Beginner
What Happens Internally?
When you use foreach, the compiler uses the dictionary’s enumerator (via GetEnumerator()) under the hood. It iterates through the internal hash buckets where key–value pairs are stored.
This approach ensures that you don’t need to manage iteration manually and it handles all the complexity for you.
You can also deconstruct the key-value pair directly inside the foreach loop for cleaner code.
foreach (var (key, value) in dict)
{
Console.WriteLine($"Key {key} Value : {value}");
}foreach(var item in dict) {
Console.WriteLine($"item : {item} \n\t Key {item.Key} Value : {item.Value}");
}If you only need keys or values, it’s more efficient to iterate directly through .Keys or .Values.
It is helpful, in many real-world scenarios, Where you may only need to access keys or values from a Dictionary<TKey, TValue>, not both.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Dictionary<string, string> dict = new()
{
{ "language", "C#" },
{ "topic", "Dictionary" },
{ "level", "Beginner" }
};
Console.WriteLine("Keys:");
foreach (var key in dict.Keys)
{
Console.WriteLine(key);
}
Console.WriteLine("\nValues:");
foreach (var value in dict.Values)
{
Console.WriteLine(value);
}
}
}Keys: language topic level Values: C# Dictionary Beginner
Modifying the dictionary while iterating dictionary or over Keys / Values will throw an InvalidOperationException. Always use a copy if modification is required. like
foreach (var key in dict.Keys.ToList())
{
dict.Remove(key);
}2. Using for Loop with LINQ
Unlike List<T> or arrays, the Dictionary<TKey, TValue> in C# does not support direct indexing (like dict[0]). That’s because a dictionary is a hash-based collection, not an index-based. Elements are stored according to their hash codes, not their insertion order.
However, you can still access items by position using LINQ’s ElementAt() method, which allows simulated index-based iteration.
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
Dictionary<string, string> dict = new()
{
{"language", "C#"},
{"topic", "Dictionary Iteration"},
{"level", "Intermediate"}
};
for (int i = 0; i < dict.Count; i++)
{
var item = dict.ElementAt(i);
Console.WriteLine($"Index: {i} | Key: {item.Key} | Value: {item.Value}");
}
}
}Index: 0 | Key: language | Value: C# Index: 1 | Key: topic | Value: Dictionary Iteration Index: 2 | Key: level | Value: Intermediate
- The ElementAt() method (from System.Linq) retrieves an element at a specific position within an enumerable sequence.
- Internally, it enumerates items one by one until it reaches the given index.
- This means each call to ElementAt() performs an O(n) operation.
Note : So, using ElementAt() inside a loop results in O(n²) complexity , fine for small dictionaries, but inefficient for large data sets.
For performance-sensitive tasks, prefer foreach or convert dictionary to a List first.
var items = dict.ToList();
for (int i = 0; i < items.Count; i++)
{
Console.WriteLine($"Index: {i} | Key: {items[i].Key} | Value: {items[i].Value}");
}This approach is O(n) overall since the conversion happens once.
3. Using ParallelEnumerable.ForAll() : Efficient Parallel Iteration for Large Data
When working with large dictionaries or computationally heavy operations, iterating sequentially using a foreach loop might become slow. C# offers a powerful solution through PLINQ (Parallel LINQ) which can distribute work across multiple CPU cores, processing elements concurrently.
By combining AsParallel() and ForAll(), you can iterate over all dictionary elements in parallel, maximizing performance for CPU-bound workloads.
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
Dictionary<string, string> dict = new()
{
{"language", "C#"},
{"topic", "Dictionary"},
{"level", "Beginner"},
{"type", "Parallel Iteration"},
{"performance", "High"}
};
dict.AsParallel().ForAll(item =>
{
Console.WriteLine($"Key: {item.Key} | Value: {item.Value}");
});
}
}Key: topic | Value: Dictionary Key: performance | Value: High Key: language | Value: C# Key: type | Value: Parallel Iteration Key: level | Value: Beginner
How It Works (Internal Behavior)
- AsParallel() converts the dictionary into a parallel query, enabling multiple threads to process different portions of the data simultaneously.
- The runtime automatically partitions the source data among available CPU cores.
- ForAll() executes the provided lambda (item => { ... }) in parallel on those partitions
- Each thread processes its assigned elements independently, improving throughput.
This parallelism significantly speeds up CPU-intensive tasks, such as :- Data transformations, Filtering and computations, Writing logs or exporting data etc
Important Notes
| Concept | Description |
|---|---|
| Order | Parallel processing doesn’t guarantee iteration order results may appear mixed. |
| Thread Safety | Avoid modifying shared state (like writing to a shared variable or list) unless you use thread-safe mechanisms (e.g., locks or concurrent collections). |
| Best Use Case | Ideal for large datasets or CPU-heavy operations where sequential iteration becomes slow. |
| Avoid For Small Data | For small dictionaries, parallel overhead may outweigh the benefits. |
4. Using String.Join() : Quick and Clean Way to Print a Dictionary
When debugging or logging data, you may want to quickly view dictionary contents without writing loops. C#’s String.Join() method makes it easy to combine all key-value pairs into a readable string, perfect for logging, debugging or quick visual inspection.
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
Dictionary<string, string> dict = new()
{
{"language", "C#"},
{"topic", "Dictionary"},
{"level", "Beginner"}
};
Console.WriteLine("Full Dictionary:");
Console.WriteLine(string.Join(", ", dict.Select(kv => $"[{kv.Key}, {kv.Value}]")));
Console.WriteLine("\nKeys:");
Console.WriteLine(string.Join(", ", dict.Keys));
Console.WriteLine("\nValues:");
Console.WriteLine(string.Join(", ", dict.Values)));
}
}Full Dictionary: [language, C#], [topic, Dictionary], [level, Beginner] Keys: language, topic, level Values: C#, Dictionary, Beginner
