Введение
QList — основной контейнер Qt, а в Qt 6 ещё и тот же класс, что QVector. Сортировка QList выполняется стандартным алгоритмом std::sort, а устаревший qSort в Qt 6 удалён. В этой статье собраны практические примеры сортировки QList с использованием std::sort: числа и строки, обратный порядок, строки без учёта регистра и по правилам русского алфавита, «естественная» сортировка имён файлов, пользовательские структуры и сортировка по нескольким полям.
Сортировка QList: числа и строки
std::sort принимает итераторы QList так же, как итераторы std::vector:
#include <QList>
#include <QString>
#include <algorithm>
QList<int> numbers = {5, 3, 8, 1};
std::sort(numbers.begin(), numbers.end()); // 1 3 5 8
QList<QString> names = {"Charlie", "Alice", "Bob"};
std::sort(names.begin(), names.end()); // Alice Bob Charlie
Для строк QString::operator< сравнивает коды символов Unicode. Это быстро, но не учитывает регистр и правила языка: строка «alice» окажется после «Zed», потому что строчные латинские буквы имеют большие коды, чем заглавные.
Сортировка по убыванию
#include <functional>
std::sort(names.begin(), names.end(), std::greater<QString>());
// или лямбдой
std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; });
Для std::greater нужен заголовок <functional>.
Строки без учёта регистра: QStringList::sort
Для списка строк удобнее метод QStringList::sort(), который умеет игнорировать регистр:
QStringList list = {"banana", "Apple", "cherry", "apple"};
list.sort(Qt::CaseInsensitive); // Apple apple banana cherry
То же самое через std::sort выглядит так:
std::sort(list.begin(), list.end(), [](const QString &a, const QString &b) {
return QString::compare(a, b, Qt::CaseInsensitive) < 0;
});
Русский алфавит и «естественная» сортировка: QCollator
Чтобы строки с кириллицей, буквой «ё» и смешанным регистром сортировались так, как ожидает пользователь, используйте QCollator. Он сравнивает строки по правилам выбранной локали:
#include <QCollator>
QStringList words = {"ёж", "Яблоко", "арбуз", "Ель", "банан"};
QCollator collator(QLocale(QLocale::Russian));
collator.setCaseSensitivity(Qt::CaseInsensitive);
std::sort(words.begin(), words.end(), collator);
// арбуз банан Ель ёж Яблоко
Объект QCollator можно передать прямо в std::sort как компаратор. Включите числовой режим, и имена с номерами будут сортироваться «по-человечески»:
QStringList files = {"file10.txt", "file2.txt", "file1.txt"};
QCollator collator;
collator.setNumericMode(true);
std::sort(files.begin(), files.end(), collator);
// file1.txt file2.txt file10.txt (а не file1, file10, file2)
Сортировка пользовательских структур
struct Person {
QString name;
int age;
};
QList<Person> people = {{"Иван", 30}, {"Анна", 25}, {"Пётр", 35}};
// по возрасту
std::sort(people.begin(), people.end(), [](const Person &a, const Person &b) {
return a.age < b.age;
});
// по имени с учётом русского алфавита
QCollator collator(QLocale(QLocale::Russian));
std::sort(people.begin(), people.end(), [&](const Person &a, const Person &b) {
return collator.compare(a.name, b.name) < 0;
});
Сортировка по нескольким полям
Если нужно отсортировать сначала по одному полю, а при равенстве — по другому, сравнивайте поля по очереди или используйте std::tie:
#include <tuple>
std::sort(people.begin(), people.end(), [](const Person &a, const Person &b) {
return std::tie(a.age, a.name) < std::tie(b.age, b.name);
});
Другой способ — сначала отсортировать по второстепенному полю, а затем по основному с помощью std::stable_sort. Стабильная сортировка сохранит порядок записей с одинаковым значением основного поля.
Советы
- Подключайте
<algorithm>явно, не рассчитывайте на косвенное включение. - Для строк, которые видит пользователь, используйте QCollator, а не
operator<. - Если QList разделяет данные с другой копией (implicit sharing), вызов
begin()выполнит отсоединение. Это нормально, но не держите старые итераторы. - Сортировка списка указателей
QList<Person*>требует компаратора, разыменовывающего указатели. Иначе будут сравниваться адреса.
Заключение
std::sort покрывает все типичные задачи: числа, строки, структуры. Для текстов на русском языке и имён с номерами подключайте QCollator, для сортировки без учёта регистра достаточно QStringList::sort(Qt::CaseInsensitive). Основы алгоритма описаны в статье Использование std::sort в C++, а сортировка ассоциативных контейнеров — в статье Как отсортировать QMap и QSet.