Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a list and handle None values properly?

Tags:

python

I am trying to sort a list of objects using the date attribute with

list_of_objects.sort(key=lambda x: x.date, reverse=True)

but some dates are just None, which means that I get the error

TypeError: can't compare datetime.datetime to NoneType

is there a way to account for this? e.g. Have objects with date == None at the top or bottom of the sorted list—or do I need to do this manually?

like image 403
carl Avatar asked Jan 12 '18 21:01

carl


People also ask

How do you sort a list without altering the content of the original list?

If you want to create a new sorted list without modifying the original one, you should use the sorted function instead. As you can notice, both sort and sorted sort items in an ascending order by default.

How do you sort a numbered list?

You can sort a one-level bulleted or numbered list so the text appears in ascending (A to Z) or descending (Z to A) alphabetical order. Select the list you want to sort. Go to Home > Sort. Set Sort by to Paragraphs and Text.

What is difference between sort () and sorted in case of list?

list. sort() sorts the list and replaces the original list, whereas sorted(list) returns a sorted copy of the list, without changing the original list.

Can you sort a list with different data types?

sort() only works for sorting lists. sorted() function is more versatile as we can use it to sort other data types and objects. Today we will see how to sort lists, tuples and dictionaries using the sorted() function.


2 Answers

You want to sort based on two properties:

  1. Primarily, whether a date is present
  2. Secondarily, the date (if present)

You can express your intent in a straightforward manner by sorting on a tuple, where

  1. the first element of the tuple specifies whether the date is None, and
  2. the second element of the tuple is the date itself.
list_of_objects.sort(key=lambda x: (x.date is None, x.date), reverse=True)

This approach circumvents the type error that you are getting, because comparison between tuples is performed left-to-right lazily. The second tuple elements don't get compared unless the first elements are equal.

Here are some examples demonstrating the concept:

>>> xs = [None, 1, 3, None, 2]

>>> sorted(xs, key=lambda x: (x is None, x))
[1, 2, 3, None, None]

>>> sorted(xs, key=lambda x: (x is not None, x))
[None, None, 1, 2, 3]

>>> sorted(xs, key=lambda x: (x is None, x), reverse=True)
[None, None, 3, 2, 1]

>>> sorted(xs, key=lambda x: (x is not None, x), reverse=True)
[3, 2, 1, None, None]
like image 87
Chris Martin Avatar answered Sep 28 '22 05:09

Chris Martin


You can modify your lambda slightly:

from datetime import datetime

list_of_objects.sort(key=lambda x: x.date or datetime.min, reverse=True)

If they're appearing at the wrong end of the sort, use datetime.max instead.

like image 37
wim Avatar answered Sep 28 '22 06:09

wim