Пользовательские сравнения функции сортировки, как это было предложено в существующих ответах, действительно позволяют легко сортировать в смеси восходящего и убывающие заказы - но они имеют серьезные проблемы с производительностью и были удалены в Python 3, оставив только предпочтительный подход к настройке - пользовательский key-extract функции ... гораздо более быстрые, хотя и более деликатные для использования в относительно редких случаях использования смешанных по возрастанию/убыванию.
В Python 2.*
, который поддерживает любой вид настройки (не как в одном вызове к sort
или sorted
:-), функция пользовательского сравнения может быть передан в качестве аргумента cmp=
имени; или, пользовательская функция извлечения ключа может быть передана как аргумент key=
с именем. В Python 3.*
доступен только последний вариант.
Это определенно стоит понять подход к изъятию ключа, даже если вы считаете, что вместо этого вы решили только проблему с использованием пользовательского сравнения: не только для производительности, но и для будущей проверки (Python 3) и для общности (подход key=
также применим к min
, max
, itertools.groupby
... гораздо более общий, чем подход cmp=
!).
Key-extract очень просто, когда все ключевые подполя сортируются одинаково (все восходящие или все нисходящие) - вы просто извлекаете их; это все еще довольно легко, если подполя, который идет «по-другому», это числа (вы просто меняете свой знак при извлечении); деликатный случай - это именно тот, который у вас есть - несколько строковых полей, которые должны сравниваться в противоположных направлениях.
Разумно простой подход к решению вашей проблемы крошечного класс регулировочной прокладки:
class Reverser(object):
def __init__(self, s): self.s = s
def __lt__(self, other): return other.s < self.s
def __eq__(self, other): return other.s == self.s
Обратите внимание, что у вас есть только поставить __lt__
и __eq__
(в <
и ==
операторах) - sort
и друзья синтезировать все другие при необходимости, на основе этих двух.
Итак, вооружившись этим небольшим вспомогательным инструментом, мы можем приступить легко ...:
def getkey(tup):
a, b = tup[0].split('_')
return Reverser(a), b
my_list.sort(key=getkey)
Как вы видите, как только вы «получить» реверс и основные концепции извлечения, вы платите по существу нет цены используя извлечение ключа вместо выборочного сравнения: код, который я предлагаю, - это 4 оператора для класса реверса (который вы можете написать один раз и помещать в свой «мешок с мешками» где-то), три для функции извлечения ключей и, конечно, один для sort
или sorted
call - всего восемь против 4 + 1 == 5 пользовательского метода сравнения в самой компактной форме (т.е. тот, который использует либо cmp с изменением знака, либо cmp с замененным аргументом NTS). Три заявления не являются большой ценой, чтобы заплатить за преимущества ключевого извлечения! -)
Производительность явно не большая проблема с таким коротким списком, но с еще более скромным (10 раз) одним ...:
# my_list as in the Q, my_cmp as per top A, getkey as here
def bycmp():
return sorted(my_list*10, cmp=my_cmp)
def bykey():
return sorted(my_list*10, key=getkey)
...
$ python -mtimeit -s'import so' 'so.bykey()'
1000 loops, best of 3: 548 usec per loop
$ python -mtimeit -s'import so' 'so.bycmp()'
1000 loops, best of 3: 995 usec per loop
Т.е., key=
подхода уже демонстрирует прирост производительности почти в два раза (сортировка списка в два раза быстрее) при работе в списке 50-ти пунктов - стоит скромной цены «8 линий, а чем 5 ", особенно со всеми другими преимуществами, о которых я уже упоминал!
Вау, мне нравится ваше решение. Я не знал, что подход cmp = имел такой штраф. –
@Steven, tx - yep, не все понимают, почему cmp = был удален в Python 3 (как «привлекательная неприятность», которая соблазняет людей страдать от штрафа за производительность!), Именно поэтому я разместил это подробное объяснение, поэтому спасибо для подтверждения это может помочь! -) –
@Alex: Я стесняюсь отредактировать один из * ваших * ответов, но, возможно, my_list.key (cmp = my_cmp) должен быть my_list.sort (key = getkey)? –