Эта статья возникла из личного публичного аккаунта:TechFlow, оригинальность это не просто, прошу внимания
В сегодняшней статье рассказывается о сортировке в Python.Как и многие языки высокого уровня, Python инкапсулирует зрелые функции сортировки. Нам нужно только вызвать внутреннюю функцию сортировки, чтобы завершить сортировку. Однако в реальных сценариях применение сортировки часто бывает более сложным. Например, тип объекта имеет несколько полей. Мы хотим сортировать по указанным полям или мы хотим сортировать по нескольким ключевым словам. В настоящее время это не может быть решено. простыми вызовами функций.
лексикографическая сортировка
Сначала рассмотрим наиболее распространенный сценарий сортировки по словарям Предположим, у нас есть массив словарей с несколькими полями в словаре. Мы хотим иметь возможность сортировать по полю в словаре.В качестве примера возьмем фактические данные:
kids = [
{'name': 'xiaoming', 'score': 99, 'age': 12},
{'name': 'xiaohong', 'score': 75, 'age': 13},
{'name': 'xiaowang', 'score': 88, 'age': 15}
]
Дети здесь представляют собой массив типа dict, а dict имеет три поля: имя, оценка и возраст. Предположим, теперь мы хотим иметь возможность сортировать по счету, что нам делать?
Есть много решений этой проблемы.Во-первых, мы можем использовать анонимную функцию, упомянутую в предыдущей статье, чтобы указать порядок. Использование здесь такое же, как использование приоритетной очереди в предыдущей статье.Давайте посмотрим непосредственно на код:
sorted(kids, key=lambda x: x['score'])
В анонимной функции x, который мы получаем, является элементом в kids, который является dict, поэтому, если мы хотим указать нужное нам поле, нам нужно использовать dict для доступа к элементу, то есть использовать квадратные скобки для найти значение соответствующего поля.
Что, если мы хотим отсортировать по нескольким ключевым словам?
Во-первых, давайте введем сортировку по нескольким ключевым словам или используем приведенные выше данные в качестве примера. В приведенном выше примере баллы у каждого ребенка разные, поэтому результат сортировки определен. Но если есть два человека с одинаковым счетом, и я хочу, чтобы младший пришел первым, что мне делать? Когда мы анализируем его, мы можем обнаружить, что он изначально был отсортирован по баллам от меньшего к большему, но могут быть случаи, когда баллы равны. В настоящее время мы хотим иметь возможность сравнивать возраст по одной и той же оценке, то есть мы хотим сортировать по двум ключевым словам, первое ключевое слово — это оценка, а второе ключевое слово — это возраст.
Поскольку Python поддерживает сортировку типов кортежей и списков, что означает, что мы можем напрямую сравнивать соотношение размеров между [1, 3] и [1, 2], Python будет автоматически сравнивать размер элементов в двух массивах одновременно. . Если он равен, он будет автоматически сравниваться в обратном направлении, пока не будет неравенство или конец.
Как только вы это понимаете, это на самом деле довольно просто. Нам просто нужно немного изменить его в анонимной функции, чтобы добавить поле к возвращаемому ею результату.
sorted(kids, key=lambda x: (x['score'], x['age']))
itemgetter
В дополнение к анонимным функциям в Python также есть собственная библиотека для решения этой проблемы. Использование очень близко к анонимным функциям, и его немного проще использовать.
Это функция получения элементов в библиотеке операторов, давайте посмотрим на код напрямую:
from operator import itemgetter
sorted(kids, key=itemgetter('score'))
Если это несколько ключевых слов, вы можете передать несколько ключей:
sorted(kids, key=itemgetter('score', 'age'))
сортировка объектов
Далее давайте посмотрим на пользовательскую сортировку объектов.Сначала мы напишем приведенный выше dict как объект:
class Kid:
def __init__(self, name, score, age):
self.name = name
self.score = score
self.age = age
def __repr__(self):
return 'Kid, name: {}, score: {}, age:{}'.format(self.name, self.score, self.age)
Чтобы было удобно наблюдать за результатом печати, мы перегрузили метод __repr__, который можно просто рассматривать как метод toString в Java, чтобы мы могли указать результат вывода при его печати.
Точно так же оператор также предоставляет функцию фактора сортировки объекта.Использование такое же, как и у получателя элементов, но имя другое.
from operator import attrgetter
kids = [Kid('xiaoming', 99, 12), Kid('xiaohong', 75, 13), Kid('xiaowang', 88, 15)]
sorted(kids, key=attrgetter('score'))
Мы также можем использовать анонимную функцию lambda для достижения этой цели:
sorted(kids, key=lambda x: x.score)
пользовательская сортировка
Это еще не конец, потому что есть еще некоторые проблемы, которые не могут быть решены. Хоть мы и внедрили сортировку по нескольким ключевым словам, остается нерешаемая проблема, а именно порядок сортировки.
Мы можем передать reverse=True в параметрах отсортированной функции, чтобы контролировать, находится ли она в положительном или обратном порядке, но если я использую несколько ключевых слов, что, если я хочу следовать определенному ключевому слову в порядке возрастания и определенному ключевому слову в порядке убывания? приказ? Например, если мы хотим отсортировать по баллам в порядке убывания, а по возрасту — в порядке возрастания, мы не можем решить это в обратном порядке — это проблема, которая не может быть решена в настоящее время.
Что делать тогда?
В настоящее время необходим окончательный убийца сортировки, а именно пользовательская сортировка, упомянутая в заголовке. То есть мы реализуем функцию, которая определяет размер элемента самостоятельно, а затем позволяем sorted вызывать нашу функцию для завершения сортировки. Это также используется в таких языках, как C++ и Java.
Пользовательские функции написать не сложно, мы можем сделать это по желанию:
def cmp(kid1, kid2):
return kid1.age < kid2.age if kid1.score == kid2.score else kid1.score > kid2.score
Если вы этого не понимаете, не беда, я написал полную версию:
def cmp(kid1, kid2):
if kid1.score == kid2.score:
return kid1.age < kid2.age
else:
return kid1.score > kid2.score
После написания это еще не конец, эта функция не может быть использована напрямую, она отличается от анонимной лямбда-функции, о которой мы упоминали ранее. Предыдущая анонимная функция используется только для указания полей, поэтому мы не можем напрямую передать эту функцию ключу, и нам нужно обернуть ее в слой обработки. Однако у этого слоя обработки функции Python уже есть готовые инструменты, мы можем вызвать его напрямую, он есть в functools, давайте посмотрим на код:
from functools import cmp_to_key
sorted(kids, key=cmp_to_key(cmp))
Давайте посмотрим на исходный код функции cmp_to_key:
def cmp_to_key(mycmp):
"""Convert a cmp= function into a key= function"""
class K(object):
__slots__ = ['obj']
def __init__(self, obj):
self.obj = obj
def __lt__(self, other):
return mycmp(self.obj, other.obj) < 0
def __gt__(self, other):
return mycmp(self.obj, other.obj) > 0
def __eq__(self, other):
return mycmp(self.obj, other.obj) == 0
def __le__(self, other):
return mycmp(self.obj, other.obj) <= 0
def __ge__(self, other):
return mycmp(self.obj, other.obj) >= 0
__hash__ = None
return K
Мы видим, что внутри функции она фактически определяет класс, затем перегружает функцию сравнения в классе и, наконец, возвращает новый объект, который перегружает функцию сравнения. Эти функции __lt__, __gt__ являются перегруженными функциями сравнения в классе. Например, __lt__ — это функция оценки меньшего, а __eq__ — функция равенства. Итак, вопрос в том, можем ли мы напрямую перегрузить функцию сравнения в классе Kid, чтобы мы могли напрямую сортировать.
Ответ — да, конечно, мы можем это сделать, и на самом деле это очень распространенная практика в объектно-ориентированном программировании. По сравнению с пользовательскими функциями сравнения мы часто предпочитаем определять приоритеты в классах. Метод, реализованный в Python, также очень прост, то есть мы вручную реализуем функцию __lt__, sorted по умолчанию сначала сортирует мелкие элементы, поэтому нам нужно реализовать только функцию __lt__. Параметр, переданный в эту функцию, является другим объектом, мы можем написать логику сравнения прямо в функции. Возвращение True указывает, что текущий объект меньше другого, в противном случае он больше другого.
Прикрепляем полный код:
class Kid:
def __init__(self, name, score, age):
self.name = name
self.score = score
self.age = age
def __repr__(self):
return 'Kid, name: {}, score: {}, age:{}'.format(self.name, self.score, self.age)
def __lt__(self, other):
return self.score > other.score or (self.score == other.score and self.age < other.age)
После реализации функции сравнения мы вызываем sorted напрямую, и ее можно отсортировать без каких-либо других аргументов.
Хотя сегодняшний контент не сложный, он очень часто используется в нашем повседневном программировании, и часто бывают ситуации, когда сложные объекты и контент нужно сортировать, поэтому я надеюсь, что каждый сможет его освоить, потому что он обязательно пригодится.
На сегодняшней статье все, если вы чувствуете, что что-то приобрели, пожалуйста, следуйте ей.Отсканируйте код и обратите вниманиеЧто ж, твое маленькое усилие много значит для меня.