Python: сортировка и группировка записей
sort, sorted, ключи с разными направлениями и словарь групп для обработки записей задания №26.
В файле задания №26 одна запись обычно описывает объект несколькими полями. Сортировка меняет порядок записей, а группировка собирает вместе записи с одинаковым выбранным признаком. Эти операции выполняют разные действия: порядок по номеру ряда ещё не превращает данные в отдельные списки мест каждого ряда.
Изменение списка и новая копия
Метод a.sort() переставляет элементы списка a. Функция sorted(a) возвращает новый отсортированный список, сохраняя прежний. По умолчанию порядок возрастающий; параметр reverse=True задаёт убывание.
a = [7, 2, 7, 4]
b = sorted(a)
print(a)
print(b)
a.sort(reverse=True)
print(a)
Результаты: [7, 2, 7, 4], [2, 4, 7, 7], [7, 7, 4, 2]. Повторяющиеся значения сохранены: два груза одинаковой массы остаются двумя грузами. Превращение списка в множество перед сортировкой удалило бы один из них.
Запись a = a.sort() ошибочна для этой цели: метод возвращает None, и имя a больше не ссылается на список. Самостоятельная строка a.sort() уже выполняет нужное изменение.
Ключ задаёт сравниваемые поля
Ключ сортировки — значение, вычисляемое для каждой записи и используемое при сравнении. Пусть запись хранит начало и конец мероприятия. Для обработки по времени окончания ключ должен брать второе поле, а не первое.
rows = [(1, 9), (3, 5)]
rows.sort(
key=lambda x: x[1]
)
print(rows)
Получится [(3, 5), (1, 9)]. Выражение lambda x: x[1] задаёт короткую функцию: получает запись x и возвращает её поле с индексом один. Поля внутри записи не переставляются; меняются местами целые записи.
Несколько критериев
Пусть учебные записи содержат балл и ID. Нужно расположить их по баллу вниз, а при равном балле — по ID вверх. Ключ из двух чисел сравнивается сначала по первому, затем, только при равенстве, по второму.
rows = [(80, 9), (90, 5),
(90, 2)]
rows.sort(
key=lambda x: (
-x[0], x[1]
)
)
print(rows)
Порядок будет [(90, 2), (90, 5), (80, 9)]. Минус меняет направление только для балла. Параметр reverse=True развернул бы сравнение всего ключа и поставил бы больший ID раньше меньшего. Поэтому он не заменяет разные направления отдельных числовых полей.
Числовые поля заранее преобразуются через int(). Иначе строки "12" и "5" сравниваются по символам: первая начинается с меньшей цифры и оказывается раньше, хотя число двенадцать больше пяти. Нужный порядок определяется типом данных, а не только выбранным полем.
Сортировка Python устойчива. При равном балле сортировка только по баллу сохраняет входной порядок, а не гарантирует возрастание ID. Требуемый дополнительный критерий должен быть задан явно.
Словарь отдельных групп
Словарь связывает ключ со значением. Здесь ключ — номер ряда, значение — список занятых мест в нём. Сначала создаются группы, затем сортируется каждый список.
rows = [(2, 8), (1, 4),
(2, 3)]
groups = {}
for row, seat in rows:
if row not in groups:
groups[row] = []
groups[row].append(seat)
for row in groups:
groups[row].sort()
print(groups[2])
Печатается [3, 8]. Поля row и seat получают значения очередной пары. Проверка наличия ключа создаёт пустой список только при первом появлении ряда; повторное создание потеряло бы ранее добавленные места.
Порядок ключей словаря отражает их добавление, поэтому для обхода рядов по возрастанию используется for row in sorted(groups):. Если условие объединяет кресла одного номера в разных рядах, ключом становится номер кресла, а значениями — ряды. Ось группировки выбирается по смыслу условия.
Какие поля определяют порядок и что должно объединяться в одну группу? После этого остаётся обосновать сам выбор объектов: сортировка не доказывает, что полученный набор оптимален.