JavaRush /Курсы /C# SELF /Сортировка коллекций

Сортировка коллекций

C# SELF
29 уровень , 2 лекция
Открыта

1. Введение

Если у вас когда-либо был ящик с носками, в котором вы пытались найти пару, вы уже сталкивались с проблемой сортировки. Когда всё лежит в беспорядке, поиск нужной вещи превращается в квест. В программировании с коллекциями — та же история.

Сортировка — это процесс упорядочивания элементов коллекции по определённому критерию (например, по алфавиту, по значению, дате и т. д.). Это важно для:

  • Отображения данных пользователю (никто не любит хаос).
  • Упрощения поиска (например, бинарный поиск возможен только в отсортированных коллекциях).
  • Сравнения, отчётов, экспорта и других операций.

Вопрос на миллион: "А если у меня всего пять элементов, я могу не сортировать?" — Теоретически, да, но как только пять превращаются в пятьсот или пять тысяч, без автоматизации не обойтись.

В .NET есть два главных подхода для сортировки:

  • Изменение исходной коллекции (например, сортировка List<T> методом Sort).
  • Создание новой отсортированной копии коллекции (например, клонирование массива, а затем сортировка).

Сортировка списков с помощью метода .Sort()

Метод Sort() есть у класса List<T>, поскольку этот класс реализует интерфейс IList<T>, предоставляя доступ по индексу и возможность изменять порядок элементов.

Пример — сортировка чисел по возрастанию:


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var numbers = new List<int> { 5, 2, 9, 1, 5, 6 };
        numbers.Sort();
        Console.WriteLine("Сортировка по возрастанию:");
        foreach(var number in numbers)
        {
            Console.Write($"{number} "); // 1 2 5 5 6 9
        }
    }
}

Здесь происходит сортировка "на месте": исходный список numbers меняется, элементы в нем переставляются.

Сортировка строк

Сортировка отлично работает и для строк:


var words = new List<string> { "апельсин", "яблоко", "банан", "груша" };
words.Sort();
Console.WriteLine(string.Join(", ", words)); // апельсин, банан, груша, яблоко

Интересный факт: по умолчанию строковая сортировка идет по Unicode-порядку, а не по "человеческому" алфавиту (особенно для разных языков, учтите это при многоязычных приложениях).

2. Сортировка по собственным правилам

Иногда сортировка "по умолчанию" не подходит. Допустим, вы хотите отсортировать пользователей не по имени, а по возрасту или дате регистрации.

Сортировка с помощью лямбда-выражения (метод Sort(Comparison<T>))

Метод Sort можно вызвать так, чтобы передать специальное правило сортировки — функцию сравнения двух элементов.

Сортировка пользователей по возрасту:


class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// ...

var users = new List<User>
{
    new User { Name = "Алиса", Age = 30 },
    new User { Name = "Боб", Age = 25 },
    new User { Name = "Ева", Age = 35 }
};

users.Sort((u1, u2) => u1.Age.CompareTo(u2.Age));

foreach (var user in users)
{
    Console.WriteLine($"{user.Name}: {user.Age}");
}
// Вывод:
// Боб: 25
// Алиса: 30
// Ева: 35

Как работает эта магия? Лямбда (u1, u2) => u1.Age.CompareTo(u2.Age) возвращает отрицательное число, если u1 младше, положительное — если старше, и 0, если возраста совпадают.

Использование интерфейса IComparer<T>

Иногда хочется вынести правило сортировки в отдельный класс, например, если у вас много коллекций и сложная логика.


class UserAgeComparer : IComparer<User>
{
    public int Compare(User x, User y)
    {
        return x.Age.CompareTo(y.Age);
    }
}

// ...

var users = new List<User>{ /* ... */ };
users.Sort(new UserAgeComparer()); // теперь сортировка по возрасту

Это удобно, если сортировка нужна в разных частях программы или сортировок много.

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

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


users.Sort((u1, u2) => {
    int ageCompare = u1.Age.CompareTo(u2.Age);
    if (ageCompare != 0)
        return ageCompare;
    else
        return u1.Name.CompareTo(u2.Name);
});

Теперь сортировка сначала по возрасту, потом — по имени.

3. Сортировка копии коллекции (без изменения исходной)

Если вы не хотите менять исходный список, скопируйте его перед сортировкой:


var copy = new List<int>(numbers);
copy.Sort();

Для пользовательских объектов — то же самое:


var usersCopy = new List<User>(users);
usersCopy.Sort((a, b) => a.Age.CompareTo(b.Age));

4. Сортировка массивов

С массивами (T[]) всё тоже довольно просто:


int[] numbers = { 4, 2, 9, 7 };
Array.Sort(numbers); // изменяется исходный массив

Для "кастомной" сортировки:


Array.Sort(numbers, (a, b) => b.CompareTo(a)); // сортировка по убыванию

Обратите внимание, что Array.Sort изменяет исходный массив, а не возвращает новый. Если нужно сохранить оригинал, копируйте массив заранее:


int[] oldNumbers = { 3, 2, 1 };
int[] copy = (int[])oldNumbers.Clone();
Array.Sort(copy);

5. "Сортировка" словарей (Dictionary<TKey, TValue>)

Dictionary<TKey, TValue> — это неупорядоченная коллекция по своей сути (т. е. не гарантирует порядок при перечислении). Но иногда хочется получить "отсортированные пары".

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


var dict = new Dictionary<string, int>
{
    { "яблоко", 2 },
    { "апельсин", 5 },
    { "груша", 3 }
};

// Сортировка по ключу:
var keyValueList = new List<KeyValuePair<string, int>>(dict);
keyValueList.Sort((a, b) => a.Key.CompareTo(b.Key));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

// Сортировка по значению:
keyValueList.Sort((a, b) => a.Value.CompareTo(b.Value));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

Если нужно получить отсортированный список ключей или значений:


var sortedKeys = new List<string>(dict.Keys);
sortedKeys.Sort();

var sortedValues = new List<int>(dict.Values);
sortedValues.Sort();

Но помните, что структура Dictionary не изменяется — вы просто получаете отсортированное перечисление. В .NET 9 появится OrderedDictionary<TKey, TValue>, который сохраняет порядок элементов. Не часто, но иногда в такой структуре возникает потребность.

6. Полезные нюансы

Обязательно ли реализовывать интерфейс сравнения?

Всё просто: если вы хотите, чтобы ваши объекты "знали", как себя сравнивать (например, по дате или имени), реализуйте интерфейс IComparable<T>.


class Product : IComparable<Product>
{
    public string Name { get; set; }
    public decimal Price { get; set; }

    public int CompareTo(Product other)
    {
        return Price.CompareTo(other.Price);
    }
}

Теперь вы можете делать:


var products = new List<Product> { /* ... */ };
products.Sort(); // сортирует по цене

Если сравнение по умолчанию не устраивает — используйте IComparer<T> или передавайте лямбду, как показано выше.

Сортировка списка пользователей по алфавиту

Допустим, у нас в приложении есть список пользователей:


List<string> users = new List<string> { "Виктор", "Анна", "Екатерина", "Борис" };
users.Sort(); // теперь users отсортирован: Анна, Борис, Виктор, Екатерина

Распределение задач по срочности


class Task
{
    public string Title { get; set; }
    public int Priority { get; set; } // 1 - срочно, 2 - важно, 3 - можно отложить
}

var todo = new List<Task>
{
    new Task { Title = "Сделать домашку", Priority = 2 },
    new Task { Title = "Купить хлеб", Priority = 1 },
    new Task { Title = "Посмотреть сериал", Priority = 3 }
};

todo.Sort((a, b) => a.Priority.CompareTo(b.Priority));

foreach (var task in todo)
    Console.WriteLine($"{task.Priority}: {task.Title}");

Сравнение способов сортировки

Коллекция Изменяется ли на месте? Метод для сортировки Можно ли задавать правило?
List<T>
Да
Sort()
Да: лямбда или IComparer
T[]
Да
Array.Sort()
Да: лямбда или IComparer
Dictionary<TKey, TValue>
Нет — (создаём список и сортируем) Да: через лямбду или IComparer

7. Типичные ошибки и нюансы сортировки

Сортировка на месте — изменяет исходную коллекцию! Если исходные данные не должны меняться — копируйте их заранее.

Попытка сортировать неизменяемую коллекцию (например, ReadOnlyCollection<T>) приведёт к ошибке выполнения.

Сравнение строк по-разному на разных культурах: сортировка строк (особенно с кириллицей, умляутами и пр.) может отличаться на различных локалях. Для корректной сортировки используйте Comparer.Create(...) с нужной культурой.

Сортировка словарей не изменяет их структуру — всегда возвращается новая последовательность пар (или новый список).

Для сложного порядка используйте интерфейс IComparer<T> с вашей логикой.

Вот пример неправильной сортировки (разбейте на практические грабли):


var numbers = new List<int> { 1, 2, 3 };
var sorted = numbers.Sort(); // ОШИБКА: Sort() возвращает void!

Правильно:


numbers.Sort(); // меняет numbers на месте

// Если нужна новая коллекция:
var sorted = new List<int>(numbers);
sorted.Sort();
2
Задача
C# SELF, 29 уровень, 2 лекция
Недоступна
Сортировка списка строк в алфавитном порядке
Сортировка списка строк в алфавитном порядке
Комментарии (2)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Slevin Уровень 59
10 февраля 2026
Для такой объемной темы по разным методам и типам сортировки - давать такую задачу для обезьянки - это практически оскорбление.
Александр Уровень 48
4 февраля 2026
как-то странно под соусом сортировки подавать юным неокрепшим мозгам делегаты, лямбда-выражения/функции и парочку новых интерфейсов. то на протяжении 4х лекций про наследование и абстракцию из пустого в порожнее, то за одну лекцию кучу всего без объяснений вкидывается.