Код
#подборки

Сортировка данных в Python: что нужно знать

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

Иллюстрация: Катя Павловская для Skillbox Media

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

Сортировка — это когда мы упорядочиваем элементы в итерируемом объекте по возрастанию, убыванию или другому критерию. В Python есть два способа сортировки: с помощью встроенной функции sorted() и с использованием метода списков .sort(). Рассмотрим их подробнее.

Содержание

Валерий Линьков

Эксперт Skillbox по компьютерным сетям и кибербезопасности. Автор телеграм-канала «Кудрявый микрофон».

Основы сортировки в Python

Функция sorted() — это универсальный метод сортировки. В качестве обязательного параметра она принимает любой итерируемый объект и возвращает отсортированный список, созданный из его элементов. Эта функция не меняет исходный объект, а создаёт новый.

Синтаксис выглядит так:

sorted(iterable, key=None, reverse=False)

Параметры функции:

  • iterable — обязательный. В него передаётся итерируемый объект, который вы хотите отсортировать (список, кортеж, строка, множество, замороженное множество).
  • key — необязательный. Функция одного аргумента, которая будет применена к каждому элементу (по умолчанию None).
  • reverse — необязательный. По умолчанию sorted() сортирует объект по возрастанию — но если поставить reverse=True, можно расположить элементы в обратном порядке.

Отсортируем список с помощью функции sorted():

l = ['a', 'v', 'r', 'h', 'v', 'c', 'd', 'y', 'g', 'b']
print(sorted(l))
# Результат:
# ['a', 'b', 'c', 'd', 'g', 'h', 'r', 'v', 'v', 'y']
print(l)
# Результат:
# ['a', 'v', 'r', 'h', 'v', 'c', 'd', 'y', 'g', 'b']

Видим, что в результате сортировки появился новый список, а исходный не изменился.

Символы в Python сортируются по таблице элементов ASCII: символ с меньшим значением ASCII будет помещён раньше, чем символ с большим значением.

Для сортировки элементов списка существует метод списков .sort(). В отличие от функции sorted(), он изменяет сам список, в котором он вызван, и не возвращает никакого значения (точнее, возвращает None).

Синтаксис .sort():

list.sort(key=None, reverse=False)

Вместо list нужно указать название списка, к которому применяется метод.

Параметры у метода .sort() необязательные. Они аналогичны параметрам sorted():

  • key — определяет небольшую функцию, в качестве аргумента принимающую элемент списка. Для каждого элемента она создаёт ключ сравнения — значение, по которому будут сравниваться эти элементы (по умолчанию — None).
  • reverse — булевый аргумент, принимающий значения True или False. Если установлено значение True, список сортируется в обратном порядке (по умолчанию — False).

Рассмотрим на примере, как работает метод .sort():

lst = ['a', 'v', 'r', 'h', 'v', 'c', 'd', 'y', 'g', 'b']

print(lst.sort())
# Результат: None

print(lst)
# Результат:
# ['a', 'b', 'c', 'd', 'g', 'h', 'r', 'v', 'v', 'y']

Как мы видим, метод lst.sort() в результате выполнения вернул None, а сам список lst изменился — теперь его элементы отсортированы по возрастанию.

Важно: сортировать можно только те итерируемые объекты, которые содержат однотипные элементы. Если в списке содержатся элементы разных типов и между ними не определена операция сравнения, при выполнении .sort() или sorted() возникнет исключение TypeError.

Примеры сортировки разных итерируемых объектов

Сортировка строк. Отсортируем строку с помощью функции sorted():

s = sorted('Hello, world!')
print(s)

# Результат выполнения:
# [' ', '!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']

Мы получили список символов, отсортированных в порядке возрастания значений ASCII.

Сортировка кортежа. Так будет выглядеть результат сортировки кортежа, элементы которого — числа:

s = sorted((7, 28, 4, 22, 6, 10, 7, 18))
print(s)

# Результат выполнения:
# [4, 6, 7, 7, 10, 18, 22, 28]

В примере выше мы создали список, в котором числа отсортированы по возрастанию.

Сортировка множества. Результат сортировки множества, состоящего из строк:

s = sorted({'attfgl', '#aghj', '1', '120', '3', '23', '1000', '4g', 'ehklgf', 'b', 'йц'})

print(s)

# Результат выполнения:
# ['#aghj', '1', '1000', '120', '23', '3', '4g', 'attfgl', 'b', 'ehklgf', 'йц']

Результат — отсортированный список строк.

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

Если мы применим функцию sorted() к словарю, то получим отсортированный список ключей кода в случае, когда ключи словаря одного типа. Иначе возникнет ошибка TypeError.

original_dict = {'b': 1, 'a': 2, 'c': 3}

sorted_items = sorted(original_dict)
print(sorted_items)  # Результат: ['a', 'b', 'c']

Отсортировать словарь можно с помощью функции sorted() совместно с методом словаря .items(). Этот метод возвращает ключи и значения словаря в виде набора кортежей.

original_dict = {'b': 1, 'a': 2, 'c': 3}

# Сортировка словаря по ключам
sorted_items = sorted(original_dict.items())
print(sorted_items)  # [('a', 2), ('b', 1), ('c', 3)]

# Преобразование обратно в словарь
sorted_dict = dict(sorted_items)
print(sorted_dict)  # {'a': 2, 'b': 1, 'c': 3}

Сначала мы преобразуем набор кортежей original_dict.items() с помощью функции sorted() в список, отсортированный по ключам. Затем преобразуем список обратно в словарь с помощью функции dict().

Сортировка списка по возрастанию

На направление сортировки влияет необязательный параметр reverse. Если reverse=False (значение по умолчанию), то данные будут сортироваться от большего к меньшему.

Числовые данные. Сортируются по возрастанию их значений:

lst = [10, 8, 14, 0, 5, 4, 6, 29]
lst.sort()
print(lst)

# Результат:
# [0, 4, 5, 6, 8, 10, 14, 29]

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

lst = ['10', '8', '14', '0', '5', '4', '6', '29']
lst.sort()
print(lst)

# Результат:
# ['0', '10', '14', '29', '4', '5', '6', '8']

Это происходит потому, что сортируемые строки сравниваются посимвольно, начиная с первого символа. Если пара символов не равна, тогда результатом сравнения строк становится результат сравнения этой пары, например: '5' > '10', а '29' < '6'.

Символьные данные. Сортируются в порядке возрастания значений ASCII: символ с меньшим значением ASCII будет помещён раньше, чем символ с большим значением ASCII.

print(sorted(['a', 'v', 'r', 'A', 'd', 'g', 'b', '0', '2', '#', '%', 'ж', 'й']))

# Результат сортировки:
# ['#', '%', '0', '2', 'A', 'a', 'b', 'd', 'g', 'r', 'v', 'ж', 'й']

Большие и маленькие буквы считаются разными символами (коды ASCII для 'A' и 'a' разные, причём код 'A' меньше, чем код 'a').

Символы, отличные от букв (например, пробелы, знаки пунктуации, символы табуляции), также имеют коды ASCII и участвуют в сортировке.

Булевы значения. False идёт перед True, так как их численные эквиваленты — 0 и 1 соответственно.

booleans = [True, False, True, False, True]
print(sorted(booleans))
# Результат: [False, False, True, True, True]

Сортировка по убыванию

Если параметр reverse = False, то сортировка идёт в обратном порядке — по убыванию элементов:

l = ['a', 'v', 'r', 'h', 'v', 'c', 'd', 'y', 'g', 'b']
print(sorted(l, reverse = True))
# Результат:
# ['y', 'v', 'v', 'r', 'h', 'g', 'd', 'c', 'b', 'a']

l.sort(reverse = True)
print(l)
# Результат тот же:
#['y', 'v', 'v', 'r', 'h', 'g', 'd', 'c', 'b', 'a']

Сортировка по ключу

Ключ сортировки key в Python может быть любой функцией, которая применяется к каждому элементу в списке перед сравнением.

Принцип работы такой: к каждому элементу в списке применяется какая-то функция, а потом результаты этих функций сравниваются для определения порядка элементов.

Разберём несколько примеров.

Сортировка по длине. Если нужно отсортировать список строк в порядке возрастания длины строки, в качестве ключа сортировки используем функцию len.

words = ['cat', 'hamster', 'squirrel', 'rabbit']
sorted_words = sorted(words, key=len)
print(sorted_words)  
# Результат:
# ['cat', 'rabbit', 'hamster', 'squirrel']

Слово 'cat' — первое в списке, потому что оно самое короткое, а 'squirrel' — последнее, так как оно самое длинное.

Сортировка c помощью собственной функции. Например, можно создать функцию, которая возвращает последний символ строки, и использовать её в качестве ключа сортировки.

def last_char(s):
    return s[-1]

words = ['cat', 'hamster', 'squirrel', 'rabbit']
sorted_words = sorted(words, key=last_char)
print(sorted_words)  
# Результат: ['squirrel', 'hamster', 'cat', 'rabbit']

Код сравнивает последние символы строк и сортирует список по их возрастанию.

Сортировка с помощью лямбда-функции. lambda в Python — это анонимная функция, принимающая любое количество аргументов, но имеющая только одно выражение, которое выполняется и возвращает результат. В качестве ключа сортировки используется функция с одним аргументом.

Ключ сортировки особенно полезен, когда нам нужно сортировать сложные структуры данных — например, списки словарей.

people = [
    {'name': 'Helen', 'age': 24},
    {'name': 'John', 'age': 21},
    {'name': 'Sam', 'age': 19}
   ]
sorted_people = sorted(people, key=lambda p: p['age'])
print(sorted_people)  
# Результат: [{'name': 'Sam', 'age': 19}, {'name': 'John', 'age': 21}, {'name': 'Helen', 'age': 24}]

В этом примере мы используем лямбда-функцию lambda p: p['age'], которая возвращает возраст каждого человека, и таким образом сортируем записи о людях в порядке увеличения их возраста.

Сортировка со встроенными функциями. В Python есть встроенные функции, которые можно использовать в качестве ключей. Например, функцию abs можно использовать для сортировки чисел не по их реальному, а по абсолютному значению. Абсолютное значение — это его величина без учёта знака. Например, абсолютное значение числа 5 равно 5, а абсолютное значение числа −3 равно 3.

numbers = [1, -2, 3, -4, -5]
sorted_numbers = sorted(numbers, key=abs)
print(sorted_numbers)  # Результат: [1, -2, 3, -4, -5]

Стабильность сортировки

Сортировка в Python по умолчанию является стабильной. Это относится и функции sorted(), и к методу .sort().

Стабильность означает, что, когда два элемента имеют одинаковые ключи сортировки, их относительный порядок сохраняется. Это важно при последовательной сортировке — например, если у нас есть список, включающий в себя элементы с двумя и более полями. Если мы сначала отсортируем список по второму полю, а затем по первому, то порядок сортировки по второму полю сохранится.

Например:

color = [('green', 3), ('red', 1), ('blue', 2), ('green', 1), ('red', 2), ('blue', 1), ('green', 2)]

sorted_color = sorted(color, key=lambda x: x[1])  # Сортируем по второму ключу
print(sorted_color)
# Результат: [('red', 1), ('green', 1), ('blue', 1), ('blue', 2), ('red', 2), ('green', 2), ('green', 3)]

sorted_color = sorted(sorted_color, key=lambda x: x[0])  # Сортируем по первому ключу
print(sorted_color)
# Результат: [('blue', 1), ('blue', 2), ('green', 1), ('green', 2), ('green', 3), ('red', 1), ('red', 2)]

Сначала мы сортируем список кортежей по второму элементу (номеру) в порядке возрастания — от 1 до 3. Затем сортируем по первому ключу — color.

Поскольку 'blue' меньше, чем 'green' и 'red', все кортежи 'blue' стоят первыми, затем идут кортежи 'green', а после — 'red'. Но внутри каждой группы кортежей с одинаковым первым элементом порядок остался таким же, как после первой сортировки (по номеру). Это показывает стабильность сортировки.

Резюме

  • Любые итерируемые объекты в Python можно сортировать с помощью функции sorted(), а списки — с помощью метода .sort(). Функция sorted() возвращает отсортированный список, состоящий из элементов итерируемого объекта, а сам объект не меняется. Метод списка .sort() изменяет сам список.
  • По умолчанию сортировка происходит в порядке возрастания, но можно провести и в обратном — с помощью аргумента reverse, которому нужно передать значение True.
  • Чтобы определить свои собственные критерии сортировки, можно использовать ключ сортировки.
  • Разные структуры данных требуют разных методов сортировки, поэтому всегда стоит заранее обдумать, какие данные предстоит сортировать и каким методом. При работе с большим объёмом данных нужно учитывать, что одни методы могут быть более эффективными, чем другие.
  • Например, если нужно только отсортировать список, не сохраняя его оригинальное значение, то лучше использовать метод .sort() — это сэкономит память. Если же при сортировке нужно сохранить исходный объект, то используется функция sorted().

Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!

Запишите ребёнка на бесплатный урок в Skillbox Kids ➞
Учим детей программированию, веб-дизайну и разработке игр. Преподаватель — IT-эксперт — подберёт курс по интересам ребёнка. Подробности — по клику.
Узнать больше
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована