I’ve had to say this several times over the years, so I thought I’d repeat it in a place where I can just make a link to it: The Dictionary<K,V>
class in .NET does not store your data in order.
When you .Add()
or .Remove()
items from a dictionary, they get stored in whatever order the dictionary finds is most efficient. It just so happens that as long as you never .Remove()
an item, the underlying data structure ends up with the items in order when you enumerate them, but this is not guaranteed.
Here’s an example program to demonstrate that it doesn’t work the way you probably expect:
public static void Main()
{
Dictionary<string, string> fruits = new Dictionary<string, string>
{
{ "A", "Apple" },
{ "B", "Banana" },
{ "C", "Cherry"},
{ "D", "Durian" },
{ "E", "Elderberry" },
{ "F", "Fig" },
};
Console.WriteLine("Fruits:");
foreach (KeyValuePair<string, string> fruit in fruits)
{
Console.WriteLine($"{fruit.Key} -> {fruit.Value}");
}
fruits.Remove("D");
fruits.Add("G", "Grape");
Console.WriteLine("\r\nFruits:");
foreach (KeyValuePair<string, string> fruit in fruits)
{
Console.WriteLine($"{fruit.Key} -> {fruit.Value}");
}
}
You might think reading this that the first output would be in order of [A, B, C, D, E, F], and the second would go [A, B, C, E, F, G]. But that’s not the output that’s produced:
Fruits:
A -> Apple
B -> Banana
C -> Cherry
D -> Durian
E -> Elderberry
F -> Fig
Fruits:
A -> Apple
B -> Banana
C -> Cherry
G -> Grape
E -> Elderberry
F -> Fig
The new entry gets slotted in where the last one was removed, which is exactly the behavior you’d expect if you had read the underlying code, but it’s very different than what you’d expect if you just assumed everything will always have insertion order.
Moral of the story: If you need dictionary data to be ordered, don’t assume it’s ordered — explicitly order it!
- If you need things to be in insertion order, keep them in a list.
- If you need things to be ordered by key, consider a
SortedDictionary<K,V>
instead. - If you only need things sometimes to be ordered by key, use Linq:
dictionary.OrderBy(pair => pair.Key)