Ответ 1
Вариант 1:
key=lambda d:(d['rank']==0, d['rank'])
Вариант 2:
key=lambda d:d['rank'] if d['rank']!=0 else float('inf')
Демо:
"Я бы хотел сортировать его по значениям ранга, упорядочиваясь следующим образом: 1-2-3-4-0-0-0". --Оригинальный плакат
>>> sorted([0,0,0,1,2,3,4], key=lambda x:(x==0, x))
[1, 2, 3, 4, 0, 0]
>>> sorted([0,0,0,1,2,3,4], key=lambda x:x if x!=0 else float('inf'))
[1, 2, 3, 4, 0, 0]
Дополнительные комментарии:
"Пожалуйста, не могли бы вы объяснить мне (новичок Python), что он делает? Я вижу, что это лямбда, которую я знаю, анонимная функция: какой бит в скобках?" - Комментарий к проекту
Обозначение индексирования/среза:
itemgetter('rank')
- это то же самое, что и lambda x: x['rank']
- это то же самое, что и функция:
def getRank(myDict):
return myDict['rank']
[...]
называется обозначением индексирования/среза, см. Объяснить нотацию фрагмента Python - Также обратите внимание, что someArray[n]
является общей нотацией на многих языках программирования для индексирования, но может не поддерживать срезы формы [start:end]
или [start:end:step]
.
key=
vs cmp=
против богатого сравнения:
Что касается того, что происходит, есть два общих способа указать, как работает алгоритм сортировки: один с функцией key
, а другой - с функцией cmp
(теперь устаревший в python, но много более универсальный). В то время как функция cmp
позволяет произвольно указать, как должны сравниваться два элемента (ввод: a
, b
; output: a<b
или a>b
или a==b
). Несмотря на то, что это законно, это не дает нам большой пользы (нам пришлось бы дублировать код неловко), а ключевая функция более естественна для вашего дела. (См. "Сравнение с богатым объектами" для того, как неявно определять cmp=
элегантным, но, возможно, чрезмерным образом.)
Реализация ключевой функции:
К сожалению, 0 является элементом целых чисел и, следовательно, имеет естественный порядок: 0 обычно < 1,2,3... Таким образом, если мы хотим наложить дополнительное правило, нам нужно отсортировать список на "более высоком уровне". Мы делаем это, заставляя ключ кортежем: кортежи сортируются сначала по их 1-му элементу, затем по их 2-му элементу. Истина всегда будет упорядочена после Ложь, поэтому все Trues будут заказаны после Falses; они будут сортироваться как обычно: (True,1)<(True,2)<(True,3)<...
, (False,1)<(False,2)<...
, (False,*)<(True,*)
. Альтернатива (вариант 2) просто присваивает словарям-0 словаря значение бесконечности, так как это гарантировано выше любого возможного ранга.
Более общая альтернатива - сравнение с богатыми объектами:
Еще более общим решением было бы создать класс, представляющий записи, а затем реализовать __lt__
, __gt__
, __eq__
, __ne__
, __gt__
, __ge__
, а все остальные богатые операторы сравнения или, наоборот, просто реализовать один из них и __eq__
и использовать @functools.total_ordering
декоратор. Это заставит объекты этого класса использовать пользовательскую логику всякий раз, когда вы используете операторы сравнения (например, x=Record(name='Joe', rank=12)
y=Record(...)
x<y
); поскольку функция sorted(...)
использует <
и другие операторы сравнения по умолчанию в сортировке, это автоматически сделает поведение при сортировке, а в других случаях, когда вы используете <
и другие операторы сравнения. Это может быть или не быть чрезмерным в зависимости от вашего варианта использования.
Чистая альтернатива - не перегружать 0 семантикой:
Однако я должен отметить, что это немного искусственно, чтобы поставить 0s за 1,2,3,4 и т.д. Является ли это оправданным, зависит от того, действительно ли rank = 0 означает rank = 0; если rank = 0 действительно "ниже", чем rank = 1 (которые, в свою очередь, действительно "ниже", чем rank = 2...). Если это действительно так, то ваш метод отлично подходит. Если это не так, то вы можете исключить запись 'rank':...
, а не устанавливать 'rank':0
. Затем вы можете сортировать Лев Левицкий с помощью 'rank' in d
или по:
Вариант 1 с другой схемой:
key=lambda d: (not 'rank' in d, d['rank'])
Вариант 2 с другой схемой:
key=lambda d: d.get('rank', float('inf'))
sidenote: Опираясь на существование бесконечности в python, почти граничит с хаком, делая любое из упомянутых решений (кортежи, сравнение объектов), Lev filter-then-concatenate solution и даже, возможно, немного более сложное cmp
решение (напечатано wilson), более обобщенное для других языков.