ZetCode

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.

Program.cs
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.

Program.cs
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.

Program.cs
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.

Program.cs
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.

Program.cs
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.

Program.cs
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.

Program.cs
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

Enumerable.OrderBy method

In this article we sorted Dictionary elements in C#.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all C# tutorials.