2013-11-08 3 views
5

Я рассортировать список dicts с помощью ключа:Как отсортировать список с «нонами последними»

groups = sorted(groups, key=lambda a: a['name']) 

некоторые из dicts имеет имя, установленное в None и Python 2 места None значения перед тем любой другой, поэтому они помещаются в списке отсортированного списка. Наивное исправление будет

groups = sorted(groups, key=lambda a: a['name'] or 'zzzz') 

но, очевидно, это не сработает для любых нелатинских имен.

Что такое красивый и путинский способ сортировки списка, содержащего значения None, чтобы эти значения были помещены в конце списка?

+0

FWIW, используя список пользовательского класса, который вы создаете, будет делать это тривиально. – dstromberg

ответ

14

Вы можете сделать это, набрав его на кортеж:

groups = sorted(groups, key=lambda a: (a['name'] is None, a['name'])) 

Это работает, потому что Python сравнивает кортежи лексически (на первый элемент, а затем на второй, чтобы разорвать связи), а также из-за Ложные сортируется раньше, чем True. Список групп, как

[{'name': 0}, {'name': 1}, {'name': 2}, {'name': 3}, {'name': 4}, {'name': None}] 

станут

[(False, 0), (False, 1), (False, 2), (False, 3), (False, 4), (True, None)] 

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

+0

умный, хотя вы можете объяснить, почему он работает :) – mgilson

+0

Я уверен, что [Сортировка КАК] (http://docs.python.org/3/howto/sorting.html) в официальных документах объясняет это где-то. Даже если это не так, это все еще один очевидный способ сделать это, это просто не так очевидно. :) – abarnert

+0

Это очень умно, спасибо :) Хотя 10-символьное изменение в коде потребовало 4 строки комментариев, чтобы объяснить, как это работает :)) – Sergey

2

Вы можете создать свой собственный «бесконечность» объект:

from functools import total_ordering 

@total_ordering 
class Infinity: 
    def __eq__(self, other): 
     return type(other) == Infinity 
    def __lt__(self, other): 
     return False 

Используйте это как так:

>>> lis = [{'name': 1}, {'name': None}, {'name': 0}, {'name': 2}] 
>>> sorted(lis, key=lambda a: Infinity() if a['name'] is None else a['name']) 
[{'name': 0}, {'name': 1}, {'name': 2}, {'name': None}] 
+0

Это тоже хорошее решение, хотя, возможно, немного переборщик для моего варианта использования – Sergey

+0

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

Смежные вопросы