Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sort a list with "Nones last"

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?

like image 211
Sergey Avatar asked Nov 08 '13 21:11

Sergey


People also ask

How do you sort a list by string length?

Custom Sorting With key= For example with a list of strings, specifying key=len (the built in len() function) sorts the strings by length, from shortest to longest. The sort calls len() for each string to get the list of proxy length values, and then sorts with those proxy values.

Can you sort a list of strings?

sort() list provides a member function sort(). It Sorts the elements of list in low to high order i.e. if list is of numbers then by default they will be sorted in increasing order. Whereas, if list is of strings then, it will sort them in alphabetical order.


Video Answer


2 Answers

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.

like image 175
David Robinson Avatar answered Sep 27 '22 18:09

David Robinson


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}]
like image 29
Lambda Fairy Avatar answered Sep 27 '22 17:09

Lambda Fairy