C# sort Dictionary
last modified October 18, 2026
In this article we show how to sort Dictionary elements in C#.
Sorting
In programming, sorting means arranging elements in an ordered sequence. Over the years, several algorithms were developed to perform sorting on data, including merge sort, quick sort, selection sort, or bubble sort.
The opposite of sorting, rearranging a sequence of elements in a random or meaningless order, is called shuffling. We can sort data alphabetically or numerically. The sort key specifies the criteria used to perform the sort.
A Dictionary<TKey,TValue> is a hash table; the order of its
elements is not defined and it has no Sort method. To process the
elements in a particular order, we use LINQ's OrderBy and
OrderByDescending methods, which return a sorted sequence of
key/value pairs and leave the dictionary unchanged. If we need a collection that
is always sorted by keys, we use SortedDictionary.
C# sort Dictionary by value
In the following example, we sort a small dictionary by its values.
Dictionary<string, int> users = new()
{
["John"] = 41,
["Jane"] = 38,
["Lucy"] = 29,
["Paul"] = 24
};
var sorted = users.OrderBy(user => user.Value);
foreach (var (name, age) in sorted)
{
Console.WriteLine($"{name} is {age} years old");
}
Console.WriteLine("----------------------------");
var sorted2 = users.OrderByDescending(user => user.Value);
foreach (var (name, age) in sorted2)
{
Console.WriteLine($"{name} is {age} years old");
}
With the OrderBy and OrderByDescending methods, we sort
the dictionary by its values in ascending and descending order.
var sorted = users.OrderBy(user => user.Value);
The elements of the dictionary are KeyValuePair<string, int>
values. The lambda expression selects the sort key, here the value.
foreach (var (name, age) in sorted)
A KeyValuePair can be deconstructed into two variables directly in
the foreach statement.
$ dotnet run Paul is 24 years old Lucy is 29 years old Jane is 38 years old John is 41 years old ---------------------------- John is 41 years old Jane is 38 years old Lucy is 29 years old Paul is 24 years old
In the next example, we use the query expression syntax.
Dictionary<string, int> users = new()
{
["John"] = 41,
["Jane"] = 38,
["Lucy"] = 29,
["Paul"] = 24
};
var sorted = from pair in users
orderby pair.Value
select pair;
foreach (var (name, age) in sorted)
{
Console.WriteLine($"{name} is {age} years old");
}
Console.WriteLine("------------------------");
var sorted2 = from pair in users
orderby pair.Value descending
select pair;
foreach (var (name, age) in sorted2)
{
Console.WriteLine($"{name} is {age} years old");
}
The example sorts elements of a dictionary by its values in ascending and
descending order using LINQ query expression syntax. The compiler translates
the orderby clause into calls of OrderBy and
OrderByDescending.
$ dotnet run Paul is 24 years old Lucy is 29 years old Jane is 38 years old John is 41 years old ------------------------ John is 41 years old Jane is 38 years old Lucy is 29 years old Paul is 24 years old
C# sort Dictionary by keys
Next, we sort a dictionary by keys.
Dictionary<string, int> users = new()
{
["John"] = 41,
["Jane"] = 38,
["Lucy"] = 29,
["Paul"] = 24
};
var sorted = users.OrderBy(user => user.Key);
foreach (var (name, age) in sorted)
{
Console.WriteLine($"{name} is {age} years old");
}
Console.WriteLine("----------------------------");
var sorted2 = users.OrderByDescending(user => user.Key);
foreach (var (name, age) in sorted2)
{
Console.WriteLine($"{name} is {age} years old");
}
The example sorts dictionary elements by its keys in ascending and descending
order using OrderBy and OrderByDescending methods.
$ dotnet run Jane is 38 years old John is 41 years old Lucy is 29 years old Paul is 24 years old ---------------------------- Paul is 24 years old Lucy is 29 years old John is 41 years old Jane is 38 years old
C# sort by value, then by key
When several elements have the same value, their mutual order is given by the
order of the dictionary, which is not defined. To get a predictable result, we
add a secondary sort key with ThenBy or
ThenByDescending.
Dictionary<string, int> scores = new()
{
["Paul"] = 82,
["Anna"] = 95,
["Roger"] = 82,
["Lucy"] = 95,
["Mark"] = 70,
["Beata"] = 82
};
var sorted = scores
.OrderByDescending(e => e.Value)
.ThenBy(e => e.Key);
foreach (var (name, score) in sorted)
{
Console.WriteLine($"{score} {name}");
}
We sort the students by their scores in descending order; students with the same score are sorted by name.
$ dotnet run 95 Anna 95 Lucy 82 Beata 82 Paul 82 Roger 70 Mark
C# sort keys with a string comparer
By default, strings are compared using the rules of the current culture. We can
pass a specific comparer as the second argument of OrderBy.
using System.Globalization;
Dictionary<string, int> words = new()
{
["čerešňa"] = 1,
["cesta"] = 2,
["Dom"] = 3,
["auto"] = 4,
["Ábel"] = 5
};
var ordinal = words.OrderBy(e => e.Key, StringComparer.Ordinal);
Console.WriteLine(string.Join(" ", ordinal.Select(e => e.Key)));
var slovak = words.OrderBy(e => e.Key,
StringComparer.Create(CultureInfo.GetCultureInfo("sk-SK"), ignoreCase: false));
Console.WriteLine(string.Join(" ", slovak.Select(e => e.Key)));
We sort Slovak words in two ways.
var ordinal = words.OrderBy(e => e.Key, StringComparer.Ordinal);
The ordinal comparer compares the numeric values of the characters. It is fast
and independent of the culture, but the result is not suitable for people:
uppercase letters come before lowercase ones and accented letters come after
z.
var slovak = words.OrderBy(e => e.Key,
StringComparer.Create(CultureInfo.GetCultureInfo("sk-SK"), ignoreCase: false));
The culture-aware comparer follows the rules of the Slovak alphabet, where
č is a separate letter following c.
$ dotnet run Dom auto cesta Ábel čerešňa Ábel auto cesta čerešňa Dom
On Linux, culture-aware comparison requires the ICU library. In the globalization invariant mode, which is common in Docker images, all cultures behave like the invariant culture.
C# keep the sorted result
The OrderBy method returns a lazy sequence; the sorting is done
each time we iterate over it. To keep the sorted result, we store it in a
collection.
Dictionary<string, int> words = new()
{
["sky"] = 3,
["forest"] = 7,
["rock"] = 1,
["water"] = 5
};
List<KeyValuePair<string, int>> list = words
.OrderByDescending(e => e.Value)
.ToList();
Console.WriteLine(string.Join(", ", list));
OrderedDictionary<string, int> ordered = new(words.OrderByDescending(e => e.Value));
Console.WriteLine(string.Join(", ", ordered));
Console.WriteLine($"forest: {ordered["forest"]}");
Console.WriteLine($"first: {ordered.GetAt(0)}");
ordered.Add("cloud", 4);
Console.WriteLine(string.Join(", ", ordered));
We store the sorted elements in a list and in an ordered dictionary.
List<KeyValuePair<string, int>> list = words
.OrderByDescending(e => e.Value)
.ToList();
A list of key/value pairs keeps the order, but we lose the fast lookup by key.
OrderedDictionary<string, int> ordered = new(words.OrderByDescending(e => e.Value));
The generic OrderedDictionary<TKey,TValue>, available since
.NET 9, keeps the elements in the order of insertion and provides both lookup
by key and access by index. Converting the sorted sequence back to a regular
Dictionary with ToDictionary would not be reliable,
because Dictionary does not guarantee any order.
Console.WriteLine($"first: {ordered.GetAt(0)}");
The GetAt method returns the element at the given index.
ordered.Add("cloud", 4);
Note that the ordered dictionary does not sort the elements; a new element is appended to the end.
$ dotnet run [forest, 7], [water, 5], [sky, 3], [rock, 1] [forest, 7], [water, 5], [sky, 3], [rock, 1] forest: 7 first: [forest, 7] [forest, 7], [water, 5], [sky, 3], [rock, 1], [cloud, 4]
C# SortedDictionary
SortedDictionary represents a collection of key/value pairs
that are sorted on the key. The elements stay sorted when we add new ones.
SortedDictionary<string, int> users = new()
{
["John"] = 41,
["Jane"] = 38,
["Lucy"] = 29,
["Paul"] = 24
};
users.Add("Adam", 33);
users["Zoe"] = 19;
foreach (var (name, age) in users)
{
Console.WriteLine($"{name} is {age} years old");
}
Console.WriteLine("----------------------------");
var desc = new SortedDictionary<string, int>(users,
Comparer<string>.Create((x, y) => string.CompareOrdinal(y, x)));
Console.WriteLine(string.Join(", ", desc.Keys));
The example demonstrates the usage of the SortedDictionary.
users.Add("Adam", 33);
users["Zoe"] = 19;
The new elements are inserted at their sorted positions.
var desc = new SortedDictionary<string, int>(users,
Comparer<string>.Create((x, y) => string.CompareOrdinal(y, x)));
The order is determined by a comparer. We create a copy of the dictionary that sorts the keys in descending order; the comparer swaps the arguments of the comparison.
$ dotnet run Adam is 33 years old Jane is 38 years old John is 41 years old Lucy is 29 years old Paul is 24 years old Zoe is 19 years old ---------------------------- Zoe, Paul, Lucy, John, Jane, Adam
A SortedDictionary is a binary search tree; lookup and insertion
take O(log n) time compared to O(1) for Dictionary. We use it when
we need the elements sorted repeatedly while the collection changes. See the
SortedDictionary article for more
details.
Source
In this article we sorted Dictionary elements in C#.
Author
List all C# tutorials.