Как использовать sorted () и sort () в Python

Как использовать sorted () и sort () в Python

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

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

К концу этого руководства вы будете знать, как:

  • Реализовать базовую сортировку и упорядочение Python для структур данных

  • Различия междуsorted() и.sort()

  • Настройте сложный порядок сортировки в своем коде на основе уникальных требований

Для этого урока вам потребуются базовые знания какlists and tuples, так иsets. Эти структуры данных будут использоваться в этом руководстве, и с ними будут выполняться некоторые основные операции. Кроме того, в этом руководстве используется Python 3, поэтому пример вывода в этом руководстве может немного отличаться, если вы используете Python 2.

Free Bonus:Click here to get access to a chapter from Python Tricks: The Book, который демонстрирует вам лучшие практики Python на простых примерах, которые вы можете мгновенно применить для написания более красивого кода Pythonic.

Значения для заказа сsorted()

Чтобы начать сортировку с помощью Python, вы сначала узнаете, как сортировать как числовые, так и строковые данные.

Сортировка чисел

Вы можете использовать Python для сортировки списка с помощьюsorted(). В этом примере определяется список целых чисел, а затем вызываетсяsorted() с переменнойnumbers в качестве аргумента:

>>>

>>> numbers = [6, 9, 3, 1]
>>> sorted(numbers)
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]

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

В этом примере показаны четыре важные характеристикиsorted():

  1. Функциюsorted() определять не нужно. Это встроенная функция, которая доступна в стандартной установке Python.

  2. sorted(), без дополнительных аргументов или параметров, упорядочивает значения вnumbers в порядке возрастания, то есть от наименьшего к наибольшему.

  3. Исходная переменнаяnumbers не изменяется, потому чтоsorted() обеспечивает отсортированный вывод и не меняет исходное значение на месте.

  4. Когда вызываетсяsorted(), он предоставляет упорядоченный список в качестве возвращаемого значения.

Этот последний пункт означает, чтоsorted() можно использовать в списке, а результат можно сразу присвоить переменной:

>>>

>>> numbers = [6, 9, 3, 1]
>>> numbers_sorted = sorted(numbers)
>>> numbers_sorted
[1, 3, 6, 9]
>>> numbers
[6, 9, 3, 1]

В этом примере теперь есть новая переменнаяnumbers_sorted, в которой хранится выводsorted().

Вы можете подтвердить все эти наблюдения, вызвавhelp() наsorted(). Необязательные аргументыkey иreverse будут рассмотрены позже в руководстве:

>>>

>>> # Python 3
>>> help(sorted)
Help on built-in function sorted in module builtins:

sorted(iterable, /, *, key=None, reverse=False)
    Return a new list containing all items from the iterable in ascending order.

    A custom key function can be supplied to customize the sort order, and the
    reverse flag can be set to request the result in descending order.

Technical Detail: Если вы переходите с Python 2 и знакомы с его одноименной функцией, вы должны знать о нескольких важных изменениях в Python 3:

  1. sorted() в Python 3 не имеет параметраcmp. Вместо этого для введения настраиваемой логики сортировки используется толькоkey.

  2. key иreverse должны передаваться как аргументы ключевого слова, в отличие от Python 2, где они могут передаваться как позиционные аргументы.

Если вам нужно преобразовать функцию Python 2cmp в функциюkey, попробуйтеfunctools.cmp_to_key(). Этот урок не будет охватывать какие-либо примеры использования Python 2.

sorted() можно использовать для кортежей и наборов очень похоже:

>>>

>>> numbers_tuple = (6, 9, 3, 1)
>>> numbers_set = {5, 5, 10, 1, 0}
>>> numbers_tuple_sorted = sorted(numbers_tuple)
>>> numbers_set_sorted = sorted(numbers_set)
>>> numbers_tuple_sorted
[1, 3, 6, 9]
>>> numbers_set_sorted
[0, 1, 5, 10]

Обратите внимание на то, что, хотя входом был набор и кортеж, выходом является список, потому чтоsorted() по определению возвращает новый список. Возвращенный объект может быть приведен к новому типу, если он должен соответствовать типу ввода. Будьте осторожны при попытке привести результирующий список обратно к набору, так как набор по определению неупорядочен:

>>>

>>> numbers_tuple = (6, 9, 3, 1)
>>> numbers_set = {5, 5, 10, 1, 0}
>>> numbers_tuple_sorted = sorted(numbers_tuple)
>>> numbers_set_sorted = sorted(numbers_set)
>>> numbers_tuple_sorted
[1, 3, 6, 9]
>>> numbers_set_sorted
[0, 1, 5, 10]
>>> tuple(numbers_tuple_sorted)
(1, 3, 6, 9)
>>> set(numbers_set_sorted)
{0, 1, 10, 5}

Значениеnumbers_set_sorted при приведении кset не упорядочивается, как ожидалось. Другая переменная,numbers_tuple_sorted, сохранила отсортированный порядок.

Сортировка строк

Типыstr сортируются аналогично другим итерациям, таким как список и кортеж. В приведенном ниже примере показано, какsorted() выполняет итерацию по каждому символу в переданном ему значении и упорядочивает их в выводе:

>>>

>>> string_number_value = '34521'
>>> string_value = 'I like to sort'
>>> sorted_string_number = sorted(string_number_value)
>>> sorted_string = sorted(string_value)
>>> sorted_string_number
['1', '2', '3', '4', '5']
>>> sorted_string
[' ', ' ', ' ', 'I', 'e', 'i', 'k', 'l', 'o', 'o', 'r', 's', 't', 't']

sorted() будет рассматриватьstr как список и перебирать каждый элемент. Вstr каждый элемент означает каждый символ вstr. sorted() не будет обрабатывать предложение по-разному, а отсортирует каждый символ, включая пробелы.

.split() может изменить это поведение и очистить вывод, а.join() может собрать все вместе. Мы рассмотрим конкретный порядок вывода и почему это так в ближайшее время:

>>>

>>> string_value = 'I like to sort'
>>> sorted_string = sorted(string_value.split())
>>> sorted_string
['I', 'like', 'sort', 'to']
>>> ' '.join(sorted_string)
'I like sort to'

Исходное предложение в этом примере преобразуется в список слов вместо того, чтобы оставить его какstr. Затем этот список сортируется и объединяется, чтобы снова сформироватьstr вместо списка.

Ограничения и ошибки с сортировкой Python

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

Списки с несовместимыми типами данных не могут бытьsorted()

Существуют типы данных, которые нельзя сравнивать друг с другом, используя толькоsorted(), потому что они слишком разные. Python вернет ошибку, если вы попытаетесь использоватьsorted() в списке, содержащем несопоставимые данные. В этом примереNone иint в одном списке не могут быть отсортированы из-за их несовместимости:

>>>

>>> mixed_types = [None, 0]
>>> sorted(mixed_types)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: '<' not supported between instances of 'int' and 'NoneType'

Эта ошибка показывает, почему Python не может сортировать значения, данные ему. Он пытается упорядочить значения с помощью оператора «меньше» (<), чтобы определить, какое значение ниже в порядке сортировки. Вы можете повторить эту ошибку, сравнив вручную два значения:

>>>

>>> None < 0
Traceback (most recent call last):
  File "", line 1, in 
TypeError: '<' not supported between instances of 'NoneType' and 'int'

Тот жеTypeError выдается, когда вы пытаетесь сравнить два несопоставимых значения без использованияsorted().

Если значения в списке можно сравнить и не выдастTypeError, то список можно отсортировать. Это предотвращает сортировку итераций по внутренне неупорядоченным значениям и создание вывода, который может не иметь смысла.

Например, должно ли число1 стоять перед словомapple? Однако, если итератор содержит комбинацию целых чисел и строк, которые являются числами, они могут быть преобразованы в сопоставимые типы данных с использованием понимания списка:

>>>

>>> mixed_numbers = [5, "1", 100, "34"]
>>> sorted(mixed_numbers)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: '<' not supported between instances of 'str' and 'int'
>>> # List comprehension to convert all values to integers
>>> [int(x) for x in mixed_numbers]
[5, 1, 100, 34]
>>> sorted([int(x) for x in mixed_numbers])
[1, 5, 34, 100]

Каждый элемент вmixed_numbers имеет вызовint() для преобразования любых значенийstr в значенияint. Затем вызываетсяsorted(), который может успешно сравнивать каждый элемент и предоставлять отсортированный вывод.

Python также может неявно преобразовывать значение в другой тип. В приведенном ниже примере оценка1 <= 0 является ложным утверждением, поэтому результат оценки будетFalse. Число1 может быть преобразовано вTrue как типbool, а0 преобразуется вFalse.

Несмотря на то, что элементы в списке выглядят по-разному, все они могут быть преобразованы в логические значения (True илиFalse) и сравнены друг с другом с помощьюsorted():

>>>

>>> similar_values = [False, 0, 1, 'A' == 'B', 1 <= 0]
>>> sorted(similar_values)
[False, 0, False, False, 1]

'A' == 'B' и1 <= 0 преобразуются вFalse и возвращаются в упорядоченном выводе.

Этот пример иллюстрирует важный аспект сортировки:sort stability. В Python, когда вы сортируете равные значения, они сохранят свой первоначальный порядок в выводе. Несмотря на то, что1 переместился, все остальные значения равны, поэтому они сохраняют свой исходный порядок относительно друг друга. В приведенном ниже примере все значения считаются равными и сохраняют свои исходные позиции:

>>>

>>> false_values = [False, 0, 0, 1 == 2, 0, False, False]
>>> sorted(false_values)
[False, 0, 0, False, 0, False, False]

Если вы проверите исходный порядок и отсортированный вывод, вы увидите, что1 == 2 преобразован вFalse, и весь отсортированный вывод находится в исходном порядке.

Когда вы сортируете строки, дело имеет значение

sorted() можно использовать в списке строк для сортировки значений в порядке возрастания, который по умолчанию отображается в алфавитном порядке:

>>>

>>> names = ['Harry', 'Suzy', 'Al', 'Mark']
>>> sorted(names)
['Al', 'Harry', 'Mark', 'Suzy']

Однако Python используетUnicode Code Point первой буквы в каждой строке для определения порядка сортировки по возрастанию. Это означает, чтоsorted() не будет обрабатывать именаAl иal одинаково. В этом примереord() используется для возврата точки кода Unicode первой буквы в каждой строке:

>>>

>>> names_with_case = ['harry', 'Suzy', 'al', 'Mark']
>>> sorted(names_with_case)
['Mark', 'Suzy', 'al', 'harry']
>>> # List comprehension for Unicode Code Point of first letter in each word
>>> [(ord(name[0]), name[0]) for name in sorted(names_with_case)]
[(77, 'M'), (83, 'S'), (97, 'a'), (104, 'h')]

name[0] возвращает первый символ в каждом элементеsorted(names_with_case), аord() предоставляет точку кода Unicode. Несмотря на то, чтоa стоит передM в алфавите, кодовая точка дляM стоит передa, поэтому отсортированный вывод имеет сначалаM.

Если первая буква такая же, тоsorted() будет использовать второй символ для определения порядка, а третий символ, если он такой же, и так далее, вплоть до конца строки:

>>>

>>> very_similar_strs = ['hhhhhd', 'hhhhha', 'hhhhhc','hhhhhb']
>>> sorted(very_similar_strs)
['hhhhha', 'hhhhhb', 'hhhhhc', 'hhhhhd']

Все значенияvery_similar_strs идентичны, за исключением последнего символа. sorted() будет сравнивать строки, и, поскольку первые пять символов совпадают, вывод будет основан на шестом символе.

Строки, которые содержат одинаковые значения, будут отсортированы в кратчайшие и самые длинные из-за того, что у более коротких строк нет элементов для сравнения с более длинными строками:

>>>

>>> different_lengths = ['hhhh', 'hh', 'hhhhh','h']
>>> sorted(different_lengths)
['h', 'hh', 'hhhh', 'hhhhh']

Самая короткая строкаh упорядочивается первой, а самая длинная,hhhhh, - последней.

Использованиеsorted() с аргументомreverse

Как показано в документацииhelp() дляsorted(), существует необязательный аргумент ключевого слова с именемreverse, который изменяет поведение сортировки на основе присвоенного ему логического значения. Еслиreverse назначенTrue, то сортировка будет в порядке убывания:

>>>

>>> names = ['Harry', 'Suzy', 'Al', 'Mark']
>>> sorted(names)
['Al', 'Harry', 'Mark', 'Suzy']
>>> sorted(names, reverse=True)
['Suzy', 'Mark', 'Harry', 'Al']

Логика сортировки остается той же, то есть имена сортируются по первой букве. Но результат был отменен с ключевым словомreverse, установленным наTrue.

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

>>>

>>> names_with_case = ['harry', 'Suzy', 'al', 'Mark']
>>> sorted(names_with_case, reverse=True)
['harry', 'al', 'Suzy', 'Mark']
>>> similar_values = [False, 1, 'A' == 'B', 1 <= 0]
>>> sorted(similar_values, reverse=True)
[1, False, False, False]
>>> numbers = [6, 9, 3, 1]
>>> sorted(numbers, reverse=False)
[1, 3, 6, 9]

sorted() с аргументомkey

Одним из самых мощных компонентовsorted() является аргумент ключевого словаkey. Этот аргумент ожидает, что ему будет передана функция, и эта функция будет использоваться для каждого значения в отсортированном списке для определения результирующего порядка.

Чтобы продемонстрировать базовый пример, давайте предположим, что для упорядочения определенного списка необходимо указать длину строк в списке, от самой короткой до самой длинной. Функция для возврата длины строкиlen() будет использоваться с аргументомkey:

>>>

>>> word = 'paper'
>>> len(word)
5
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=len)
['pie', 'book', 'banana', 'Washington']

Результирующий порядок представляет собой список с порядком строк от кратчайшего до самого длинного. Длина каждого элемента в списке определяетсяlen(), а затем возвращается в порядке возрастания.

Вернемся к более раннему примеру сортировки по первой букве, когда дело обстоит иначе. key можно использовать для решения этой проблемы путем преобразования всей строки в нижний регистр:

>>>

>>> names_with_case = ['harry', 'Suzy', 'al', 'Mark']
>>> sorted(names_with_case)
['Mark', 'Suzy', 'al', 'harry']
>>> sorted(names_with_case, key=str.lower)
['al', 'harry', 'Mark', 'Suzy']

Выходные значения не были преобразованы в нижний регистр, потому чтоkey не управляет данными в исходном списке. Во время сортировки переданная вkey функция вызывается для каждого элемента для определения порядка сортировки, но исходные значения будут на выходе.

Есть два основных ограничения при использовании функций с аргументомkey.

Во-первых, количество обязательных аргументов в функции, переданной вkey, должно быть равно одному.

В приведенном ниже примере показано определение функции сложения, которая принимает два аргумента. Когда эта функция используется вkey в списке чисел, она терпит неудачу, потому что отсутствует второй аргумент. Каждый раз, когдаadd() вызывается во время сортировки, он получает только один элемент из списка за раз:

>>>

>>> def add(x, y):
...     return x + y
...
>>> values_to_add = [1, 2, 3]
>>> sorted(values_to_add, key=add)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: add() missing 1 required positional argument: 'y'

Второе ограничение заключается в том, что функция, используемая сkey, должна иметь возможность обрабатывать все значения в итерируемом объекте. Например, у вас есть список чисел, представленных в виде строк, которые будут использоваться вsorted(), иkey попытается преобразовать их в числа с помощьюint. Если значение в итерируемом не может быть преобразовано в целое число, то функция завершится ошибкой:

>>>

>>> values_to_cast = ['1', '2', '3', 'four']
>>> sorted(values_to_cast, key=int)
Traceback (most recent call last):
  File "", line 1, in 
ValueError: invalid literal for int() with base 10: 'four'

Каждое числовое значение какstr может быть преобразовано вint, аfour - нет. Это вызывает увеличениеValueError и объясняет, чтоfour не может быть преобразован вint, потому что он недействителен.

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

Если требование упорядочения состоит в том, чтобы упорядочить итерацию по последней букве в каждой строке (и если буква такая же, то использовать следующую букву), то можно определитьfunction и затем использовать его при сортировке. В приведенном ниже примере определяется функция, которая переворачивает переданную ей строку, а затем эта функция используется в качестве аргумента дляkey:

>>>

>>> def reverse_word(word):
...     return word[::-1]
...
>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=reverse_word)
['banana', 'pie', 'book', 'Washington']

Синтаксис срезаword[::-1] используется для обращения строки. К каждому элементу будет примененreverse_word(), и порядок сортировки будет основан на символах в обратном слове.

Вместо написания отдельной функции вы можете использовать функциюlambda, определенную в аргументеkey.

Alambda - анонимная функция, которая:

  1. Должен быть определен в строке

  2. Не имеет имени

  3. Не может содержатьstatements

  4. Будет исполняться как функция

В приведенном ниже примереkey определяется какlambda без имени, аргумент, принимаемыйlambda, равенx, аx[::-1] - это операция что будет выполнено с аргументом:

>>>

>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=lambda x: x[::-1])
['banana', 'pie', 'book', 'Washington']

x[::-1] вызывается для каждого элемента и меняет слово. Этот обратный вывод затем используется для сортировки, но исходные слова все еще возвращаются.

Если требование изменится и порядок также должен быть изменен, тогда ключевое словоreverse можно использовать вместе с аргументомkey:

>>>

>>> words = ['banana', 'pie', 'Washington', 'book']
>>> sorted(words, key=lambda x: x[::-1], reverse=True)
['Washington', 'book', 'pie', 'banana']

Функцииlambda также полезны, когда вам нужно отсортировать объектыclass на основе свойства. Если у вас есть группа учеников и вам нужно отсортировать их по итоговой оценке, от самой высокой к самой низкой, тоlambda можно использовать для получения свойстваgrade изclass:

>>>

>>> from collections import namedtuple

>>> StudentFinal = namedtuple('StudentFinal', 'name grade')
>>> bill = StudentFinal('Bill', 90)
>>> patty = StudentFinal('Patty', 94)
>>> bart = StudentFinal('Bart', 89)
>>> students = [bill, patty, bart]
>>> sorted(students, key=lambda x: getattr(x, 'grade'), reverse=True)
[StudentFinal(name='Patty', grade=94), StudentFinal(name='Bill', grade=90), StudentFinal(name='Bart', grade=89)]

В этом примереnamedtuple используется для создания классов с атрибутамиname иgrade. lambda вызываетgetattr() для каждого элемента и возвращает значение дляgrade.

reverse устанавливается вTrue, чтобы восходящий вывод был перевернут на нисходящий, чтобы первыми располагались самые высокие оценки.

Возможности упорядочивания безграничны, если вы используете аргументы ключевого словаkey иreverse вsorted(). Код может быть чистым и коротким, если вы используете базовыйlambda для небольшой функции, или вы можете написать совершенно новую функцию, импортировать ее и использовать в ключевом аргументе.

Значения для заказа с.sort()

.sort() с очень похожим названием немного отличается от встроенногоsorted(). Они выполняют более или менее то же самое, но документацияhelp() дляlist.sort() выделяет два наиболее важных различия между.sort() иsorted():

>>>

>>> # Python2
Help on method_descriptor:

sort(...)
    L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
    cmp(x, y) -> -1, 0, 1

>>> # Python3
>>> help(list.sort)
Help on method_descriptor:

sort(...)
    L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*

Во-первых, sort - это метод классаlist и может использоваться только со списками. Это не встроенная функция с передаваемой ей итерацией.

Во-вторых,.sort() возвращаетNone и изменяет значения на месте. Давайте посмотрим на влияние обоих этих различий в коде:

>>>

>>> values_to_sort = [5, 2, 6, 1]
>>> # Try to call .sort() like sorted()
>>> sort(values_to_sort)
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'sort' is not defined

>>> # Try to use .sort() on a tuple
>>> tuple_val = (5, 1, 3, 5)
>>> tuple_val.sort()
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'tuple' object has no attribute 'sort'

>>> # Sort the list and assign to new variable
>>> sorted_values = values_to_sort.sort()
>>> print(sorted_values)
None

>>> # Print original variable
>>> print(values_to_sort)
[1, 2, 5, 6]

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

  1. Нет упорядоченного вывода.sort(), поэтому присвоение новой переменной передает только типNone.

  2. Списокvalues_to_sort был изменен, и исходный порядок никоим образом не сохраняется.

Эти различия в поведении делают.sort() иsorted() абсолютно не взаимозаменяемыми в коде, и они могут привести к совершенно неожиданным результатам, если один из них используется неправильно.

.sort() имеет те же необязательные аргументы ключевого словаkey иreverse, которые обеспечивают ту же надежную функциональность, что иsorted(). Здесь вы можете отсортировать список фраз по второй букве третьего слова и вернуть список в обратном порядке:

>>>

>>> phrases = ['when in rome',
...     'what goes around comes around',
...     'all is fair in love and war'
...     ]
>>> phrases.sort(key=lambda x: x.split()[2][1], reverse=True)
>>> phrases
['what goes around comes around', 'when in rome', 'all is fair in love and war']

В этом примереlambda используется для следующих действий:

  1. Разделить каждую фразу в список слов

  2. Найти третий элемент или слово в этом случае

  3. Найдите в этом слове вторую букву

Когда использоватьsorted(), а когда использовать.sort()

Вы видели разницу междуsorted() и.sort(), но когда вы используете что?

Допустим, скоро будет 5к гонка: первый ежегодный питон 5к. Данные из гонки должны быть собраны и отсортированы. Данные, которые должны быть получены, это номер нагрудника бегуна и количество секунд, которое потребовалось, чтобы закончить гонку:

>>>

>>> from collections import namedtuple

>>> Runner = namedtuple('Runner', 'bibnumber duration')

Когда бегуны пересекают финишную черту, каждыйRunner будет добавлен в список под названиемrunners. В гонках 5k не все бегуны пересекают стартовую линию одновременно, поэтому первый человек, который пересечет финишную черту, на самом деле не может быть самым быстрым человеком:

>>>

>>> runners = []
>>> runners.append(Runner('2528567', 1500))
>>> runners.append(Runner('7575234', 1420))
>>> runners.append(Runner('2666234', 1600))
>>> runners.append(Runner('2425234', 1490))
>>> runners.append(Runner('1235234', 1620))
>>> # Thousands and Thousands of entries later...
>>> runners.append(Runner('2526674', 1906))

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

Теперь опытный программист, отвечающий за обработку итоговых данных, видит этот список, знает, что топ-5 самых быстрых участников - победители, которые получают призы, а оставшиеся бегуны будут отсортированы по быстрейшему времени.

Не существует требований для нескольких типов сортировки по различным атрибутам. Список разумного размера. Там нет упоминания о хранении списка где-то. Просто отсортируйте по продолжительности и возьмите пять участников с наименьшей продолжительностью:

>>>

>>> runners.sort(key=lambda x: getattr(x, 'duration'))
>>> top_five_runners = runners[:5]

Программист решает использоватьlambda в аргументеkey, чтобы получить атрибутduration от каждого бегуна и отсортироватьrunners на месте, используя.sort(). После сортировкиrunners первые 5 элементов сохраняются вtop_five_runners.

Миссия выполнена! Приходит директор гонки и сообщает программисту, что, поскольку текущая версия Python 3.7, они решили, что каждый тридцать седьмой человек, который пересек финишную черту, получит бесплатную спортивную сумку.

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

Если вы работаете с важными данными и есть даже небольшая вероятность того, что исходные данные потребуется восстановить, то.sort() - не лучший вариант. Если данные являются копией, если это неважные рабочие данные, или если никто не будет возражать против их потери, потому что их можно восстановить, то.sort() может быть прекрасным вариантом.

В качестве альтернативы участники могли быть отсортированы с использованиемsorted() и того жеlambda:

>>>

>>> runners_by_duration = sorted(runners, key=lambda x: getattr(x, 'duration'))
>>> top_five_runners = runners_by_duration[:5]

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

>>>

>>> every_thirtyseventh_runners = runners[::37]

every_thirtyseventh_runners создается с использованием шага в синтаксисе среза списка наrunners, который по-прежнему содержит исходный порядок, в котором бегуны пересекли финишную черту.

Как сортировать в Python: заключение

.sort() иsorted() могут обеспечить именно тот порядок сортировки, который вам нужен, если вы правильно используете их с необязательными аргументами ключевого словаreverse иkey.

Оба имеют очень разные характеристики, когда дело касается вывода и модификаций на месте, поэтому убедитесь, что вы продумали все функции приложения или программы, которые будут использовать.sort(), поскольку они могут безвозвратно перезаписывать данные.

Для заядлых Pythonistas, ищущих проблемы с сортировкой, попробуйте использовать более сложные типы данных в сортировке: вложенные итерации. Кроме того, не стесняйтесь погрузиться в реализации кода Python с открытым исходным кодом для встроенных модулей и прочитать об используемом в Python алгоритме сортировки под названиемTimsort.