Reputation: 12417
I'm sorting a list of dicts by a key:
groups = sorted(groups, key=lambda a: a['name'])
some of the dicts have name set to None
, and Python 2 places None
values before any other, so they're placed at the front of the sorted list. A naive fix would be
groups = sorted(groups, key=lambda a: a['name'] or 'zzzz')
but, obviously, that would not work for any non-Latin names.
What is a nice and Pythonic way of sorting a list containing None
values so that those values are placed at the end of the list?
Upvotes: 5
Views: 683
Reputation: 14686
You can create your own "infinity" object:
from functools import total_ordering
@total_ordering
class Infinity:
def __eq__(self, other):
return type(other) == Infinity
def __lt__(self, other):
return False
Use it like so:
>>> 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}]
Upvotes: 2
Reputation: 78610
You can do this by keying it on a tuple:
groups = sorted(groups, key=lambda a: (a['name'] is None, a['name']))
This works because Python compares tuples lexicographically (on the first element, then on the second to break ties), and because False gets sorted earlier than True. A list of groups like
[{'name': 0}, {'name': 1}, {'name': 2}, {'name': 3}, {'name': 4}, {'name': None}]
will become
[(False, 0), (False, 1), (False, 2), (False, 3), (False, 4), (True, None)]
The tuple that starts with True
will necessarily end up at the end, and the rest, since the first value ties, will be sorted by the second value.
Upvotes: 14