Функции сортировки sort и sorted

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

sort()

или функцией

sorted()

для всех остальных типов коллекций. Давайте вначале посмотрим на отличие в их вызовах. Если у нас имеется какой-либо упорядоченный список:

a=[1,-45,3,2,100,-4]

то этот объект имеет встроенный метод sort, который меняет его состояние и расставляет элементы по возрастанию:

a.sort()

Получим измененный список:

[-45, -4, 1, 2, 3, 100]

А вот коллекции кортежи или строки:

b=("ab", "bc", "wd", "gf")
c = "hello world"

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

b.sort()
c.sort()

приведет к ошибке. Для их сортировки как раз и можно воспользоваться второй функцией sorted:

sorted(b)

на выходе получим упорядоченный список

['ab', 'bc', 'gf', 'wd']

Обратите внимание, чтобы мы не передавали в качестве аргумента функции sorted, на выходе будем получать именно список отсортированных данных. В данном случае передаем кортеж, а получаем – список.

Или же, со строкой:

sorted(c)

результатом будет упорядоченная коллекция из символов:

[' ', 'd', 'e', 'h', 'l', 'l', 'l', 'o', 'o', 'r', 'w']

Причем, эта функция не меняет исходные коллекции b и c, она возвращает новый список с отсортированными данными. В то время как метод sort для списка меняет этот список. Вот на это следует также обращать внимание. То есть, если нам нужно сохранить результат сортировки в переменной, это делается так:

res = sorted(b)

и res будет ссылаться на список:

['ab', 'bc', 'gf', 'wd']

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

a=[1,-45,3,2,100,-4, "b"]

отсортировать не получится:

a.sort()

возникнет ошибка, что строку нельзя сравнивать с числом. И то же самое с функцией sorted:

sorted(a)

Если уберем последний элемент:

a=[1,-45,3,2,100,-4]

то все будет работать:

sorted(a)

И этот пример также показывает, что список можно сортировать и с помощью метода sort и с помощью функции sorted. Разница только в том, что метод sort не создает новой коллекции, а меняет уже существующую. Функция же sorted не меняет исходную коллекцию, а создает новую с отсортированными элементами. Поэтому, для изменения коллекции a здесь следует записывать такую конструкцию:

a = sorted(a)

Оба этих подхода к сортировке поддерживают необязательный параметр

reverse = True/False

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

a = sorted(a, reverse=True)

то получим сортировку по убыванию:

[100, 3, 2, 1, -4, -45]

И то же самое с методом sort:

a.sort(reverse=True)

Своя сортирующая функция

Язык Python позволяет создавать свои сортирующие функции для более точной настройки алгоритма сортировки. Давайте для начала рассмотрим такой пример. Пусть у нас имеется вот такой список:

a=[1,4,3,6,5,2]

и мы хотим, чтобы вначале стояли четные элементы, а в конце – нечетные. Для этого создадим такую вспомогательную функцию:

def funcSort(x):
    return x%2

И укажем ее при сортировке:

print( sorted(a, key=funcSort) )

Мы здесь используем именованный параметр key, который принимает ссылку на сортирующую функцию. Запускаем программу и видим следующий результат:

[4, 6, 2, 1, 3, 5]

Разберемся, почему так произошло. Смотрите, функция funcSort возвращает вот такие значения для каждого элемента списка a:

И, далее, в sorted уже используются именно эти значения для сортировки элементов по возрастанию. То есть, сначала, по порядку берется элемент со значением 4, затем, 6 и потом 2. После этого следуют нечетные значения в порядке их следования: 1, 3, 5. В результате мы получаем список:

[4, 6, 2, 1, 3, 5]

А теперь, давайте модифицируем нашу функцию, чтобы выполнялась сортировка и самих значений:

def funcSort(x):
    if x%2 == 0:
        return x
    else:
        return x+100

Здесь четные значения возвращаются такими как они есть, а к нечетным прибавляем 100. В результате получим:

[2, 4, 6, 1, 3, 5]

Здесь элементам нашего списка ставятся в соответствие указанные числа, и по этим числам выполняется их сортировка. То есть, эти числа можно воспринимать как некие ключи, по которым и происходит сортировка элементов списка. Поэтому в Python такую сортировку называют сортировкой по ключам.

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

print( sorted(a, key=lambda x: x%2) )

Получим ранее рассмотренный результат:

[4, 6, 2, 1, 3, 5]

Или, то же самое можно делать и со строками:

lst = ["Москва", "Тверь", "Смоленск", "Псков", "Рязань"]

Отсортируем их по длине строки:

print( sorted(lst, key=len) )

получим результат:

['Тверь', 'Псков', 'Москва', 'Рязань', 'Смоленск']

Или по последнему символу, используя лексикографический порядок:

print( sorted(lst, key=lambda x: x[-1]) )

['Москва', 'Псков', 'Смоленск', 'Тверь', 'Рязань']

Или, по первому символу:

print( sorted(lst, key=lambda x: x[0]) )

['Москва', 'Псков', 'Рязань', 'Смоленск', 'Тверь']

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

books = {
("Евгений Онегин", "Пушкин А.С.", 200),
("Муму", "Тургенев И.С.", 250),
("Мастер и Маргарита", "Булгаков М.А.", 500),
("Мертвые души", "Гоголь Н.В.", 190)
}

И нам нужно его отсортировать по возрастанию цены (последнее значение). Это можно сделать так:

print( sorted(books, key=lambda x: x[2]) )

На выходе получим список:

[('Мертвые души', 'Гоголь Н.В.', 190), ('Евгений Онегин', 'Пушкин А.С.', 200), ('Муму', 'Тургенев И.С.', 250), ('Мастер и Маргарита', 'Булгаков М.А.', 500)]

Вот так можно выполнять сортировку данных в Python.

Задания для самоподготовки

1. Используя сортировку, найдите первые три наименьшие значения в списке:

a=[1,2,-5,0,5,10]

Сам список должен оставаться неизменным.

2. Отсортируйте список:

digs = (-10, 0, 7, -2, 3, 6, -8)

так, чтобы сначала шли отрицательные числа, а затем, положительные.

3. Пусть имеется словарь:

{'+7': 2345678901, '+4': 3456789012, '+5': 5678901234, '+12': 78901234}

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

+4, +5, +7, +12

Видео по теме