2025, Dec 03 00:02

Как отсортировать список списков по первому и второму элементу в Python

Как сортировать вложенные списки в Python по двум полям: сначала по первому элементу, затем по второму. Лексикографическая сортировка и ключ lambda. Примеры

Сортировка вложенных коллекций по нескольким критериям — задача привычная, но нередко вызывает вопросы, когда нужно сохранить первичный порядок и аккуратно добавить вторичный. Цель здесь проста: упорядочить список списков по первому элементу, а если первые совпадают — по второму. В реальных данных могут встречаться строки; числа в примерах взяты лишь для компактности.

Пример, показывающий проблему

Предположим, у нас есть такая структура, и мы сортируем только по первому элементу. Результат не гарантирует нужный порядок, если первые элементы равны.

rows_src = [[3, 4, 3], [2, 6, 2], [2, 5, 6]]
primary_only = sorted(rows_src, key=lambda rec: rec[0])
print(primary_only)

Такой подход учитывает только первый элемент и не разрешает «ничьи» по второму — это не то, что требуется.

Что происходит на самом деле

Нужный порядок — лексикографический: сравниваем первые элементы, а при равенстве — вторые. Именно так Python уже сравнивает последовательности — списки и кортежи. Отсюда два пути: либо сформировать ключ сортировки, который сравнивается лексикографически, либо опереться на встроенное сравнение последовательностей. Если на порядок должны влиять только первые две позиции, задайте ключ, возвращающий именно их.

Решение: два равнозначных подхода

Первый вариант — вернуть кортеж из двух первых элементов внутреннего списка. Сортировка по такому кортежу обеспечивает приоритет «сначала первый, затем второй» и не затрагивает элементы дальше этих позиций.

data_rows = [[3, 4, 3], [2, 6, 2], [2, 5, 6]]
by_two_fields = sorted(data_rows, key=lambda rec: (rec[0], rec[1]))
print(by_two_fields)
# [[2, 5, 6], [2, 6, 2], [3, 4, 3]]

Второй вариант — воспользоваться дефолтным лексикографическим сравнением списков и вызвать sorted без ключа. В этом случае учитывается сначала первый, затем второй, потом третий элемент и так далее. Если вам важно строго «первый, затем второй» и нужно игнорировать остальные позиции, верните в ключе только первые два срезом.

items = [[3, 4, 3], [2, 6, 2], [2, 5, 6]]
lex_default = sorted(items)
print(lex_default)
first_two_only = sorted(items, key=lambda rec: rec[:2])
print(first_two_only)
# [[2, 5, 6], [2, 6, 2], [3, 4, 3]]

Эти приемы одинаково работают и со строками: порядок определяется по тем же правилам — сначала сравниваются первые строки, при равенстве — вторые.

Почему это важно

При сортировке структурированных данных важно точно выразить задуманный порядок. Ключ по одному полю оставляет равные значения нерешенными — результат может казаться произвольным. Лексикографическая сортировка — будь то неявно, при прямой сортировке списков, или явно, через двухэлементный ключ — дает предсказуемый исход. Если на порядок должны влиять только конкретные позиции, ограничьте ключ ими, чтобы избежать нежелательных «тай-брейков».

Выводы

Если требуется порядок «сначала первый, затем второй», сортируйте по двум полям — например, с ключом lambda rec: (rec[0], rec[1]) — или пользуйтесь стандартным сравнением списков через sorted(your_list). А чтобы игнорировать позиции после второй, возвращайте только первые два элемента: lambda rec: rec[:2]. Так сортировка соответствует постановке задачи: первичный порядок не нарушается, а «ничьи» разрешаются последовательно.