Avatar ·

Как отсортировать словарь (Dictionary) по значению в C#?

Всем привет! Я только начинаю изучать C# и столкнулся с такой проблемой: у меня есть словарь `Dictionary`, где ключ — это имя студента, а значение — его балл за экзамен. Мне нужно вывести студентов в порядке возрастания баллов, но я не могу понять, как это сделать. Вот пример моего кода: ```csharp Dictionary scores = new Dictionary { { "Alice", 85 }, { "Bob", 92 }, { "Charlie", 78 }, { "Diana", 95 } }; // Как отсортировать этот словарь по значениям (баллам)? foreach (var pair in scores) { Console.WriteLine($"{pair.Key}: {pair.Value}"); } ``` Я знаю, что `Dictionary` сам по себе не поддерживает сортировку, так как это хеш-таблица. Но мне нужно получить упорядоченный список пар "ключ-значение" по возрастанию значения. Пробовал использовать `OrderBy`, но получаю ошибки. Подскажите, пожалуйста, как правильно это сделать? Желательно с примером кода. Заранее спасибо! <<>>

Решение с помощью LINQ и метода OrderBy

Самый простой и распространённый способ — использовать LINQ (Language Integrated Query). Метод OrderBy позволяет отсортировать коллекцию по указанному ключу. В вашем случае ключом сортировки будет значение пары (Value).

Важно понимать: Dictionary не может быть отсортирован на месте, так как его внутренняя структура (хеш-таблица) не поддерживает порядок элементов. Поэтому мы создаём новую упорядоченную коллекцию, обычно это List> или анонимный тип.

Вот полный пример кода:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        Dictionary<string, int> scores = new Dictionary<string, int>
        {
            { "Alice", 85 },
            { "Bob", 92 },
            { "Charlie", 78 },
            { "Diana", 95 }
        };

        // Сортировка по значению (по возрастанию)
        var sortedByValue = scores.OrderBy(pair => pair.Value);

        Console.WriteLine("Студенты, отсортированные по баллам (возрастание):");
        foreach (var pair in sortedByValue)
        {
            Console.WriteLine($"{pair.Key}: {pair.Value}");
        }

        // Если нужна сортировка по убыванию, используем OrderByDescending
        var sortedDescending = scores.OrderByDescending(pair => pair.Value);
        Console.WriteLine("\nСтуденты, отсортированные по баллам (убывание):");
        foreach (var pair in sortedDescending)
        {
            Console.WriteLine($"{pair.Key}: {pair.Value}");
        }
    }
}

Как это работает?

  • scores.OrderBy(pair => pair.Value) — берёт каждую пару из словаря и сортирует их по свойству Value.
  • Результат — объект типа IOrderedEnumerable<KeyValuePair<string, int>>, который можно перебирать в цикле foreach.
  • Сам словарь scores остаётся неизменным.

Сохранение результата в список

Если вам нужно не только вывести данные, но и сохранить их для дальнейшей работы, преобразуйте результат в список:

List<KeyValuePair<string, int>> sortedList = scores.OrderBy(pair => pair.Value).ToList();

Сортировка по нескольким критериям

Если значения одинаковы, можно добавить вторичную сортировку по ключу:

var sorted = scores.OrderBy(pair => pair.Value).ThenBy(pair => pair.Key);

Важные замечания

  • Не забудьте добавить using System.Linq; в начало файла.
  • Метод OrderBy возвращает новую коллекцию, исходный словарь не изменяется.
  • Для обратного порядка используйте OrderByDescending.

Этот подход работает во всех версиях .NET Framework и .NET Core/.NET 5+. Он лаконичен, читаем и использует мощь LINQ.

<<>>

Альтернативный подход: использование SortedDictionary с кастомным компаратором

Если вам нужно, чтобы словарь всегда оставался отсортированным по значению (а не только при выводе), можно использовать SortedDictionary с собственным компаратором. Однако это сложнее, так как SortedDictionary сортирует по ключу, а не по значению. Придётся создать класс-обёртку.

Вот пример для случая, когда значения уникальны:

public class ValueComparer : IComparer<int>
{
    public int Compare(int x, int y) => x.CompareTo(y);
}

// Использование:
var sortedByValue = new SortedDictionary<int, string>();
foreach (var pair in scores)
{
    sortedByValue[pair.Value] = pair.Key; // Меняем местами ключ и значение
}
// Теперь sortedByValue отсортирован по ключу (бывшему значению)

Недостатки:

  • Значения должны быть уникальными, иначе произойдёт перезапись.
  • Код менее читаем и более громоздок.

Поэтому для большинства задач рекомендуется первый способ с LINQ. Он проще и гибче.