Как использовать 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()
:
-
Функцию
sorted()
определять не нужно. Это встроенная функция, которая доступна в стандартной установке Python. -
sorted()
, без дополнительных аргументов или параметров, упорядочивает значения вnumbers
в порядке возрастания, то есть от наименьшего к наибольшему. -
Исходная переменная
numbers
не изменяется, потому чтоsorted()
обеспечивает отсортированный вывод и не меняет исходное значение на месте. -
Когда вызывается
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:
-
sorted()
в Python 3 не имеет параметраcmp
. Вместо этого для введения настраиваемой логики сортировки используется толькоkey
. -
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
- анонимная функция, которая:
-
Должен быть определен в строке
-
Не имеет имени
-
Не может содержатьstatements
-
Будет исполняться как функция
В приведенном ниже примере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()
:
-
Нет упорядоченного вывода
.sort()
, поэтому присвоение новой переменной передает только типNone
. -
Список
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
используется для следующих действий:
-
Разделить каждую фразу в список слов
-
Найти третий элемент или слово в этом случае
-
Найдите в этом слове вторую букву
Когда использовать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.