59
votes

I have a homogeneous list of objects with None, but it can contain any type of values. Example:

>>> l = [1, 3, 2, 5, 4, None, 7]
>>> sorted(l)
[None, 1, 2, 3, 4, 5, 7]
>>> sorted(l, reverse=True)
[7, 5, 4, 3, 2, 1, None]

Is there a way without reinventing the wheel to get the list sorted the usual python way, but with None values at the end of the list, like that:

[1, 2, 3, 4, 5, 7, None]

I feel like here can be some trick with "key" parameter

3
Are the values guaranteed to be ints or None, or do you need None to sort after all arbitrary objects? - abarnert
No, it can be string or None, float and None. Generally, it's homogeneous list with None elements - Nikolai Golub
@NikolayGolub: For future reference, it's better to make information like that clear in the question—after all, SethMMorton's answer fits what you asked, yet doesn't fit what you actually wanted, so you wouldn't have had a good solution if F.J hadn't happened by. - abarnert
@abarnert I was going by the first sentence, "I have homogeneous list of objects with None", so I assumed that the OP's list was not heterogeneous. - SethMMorton
@abarnert I see what you are saying. I guess this goes back to the XY discussion we had from a few days ago. I now understand why it's important to ask "Why?". - SethMMorton

3 Answers

151
votes
>>> l = [1, 3, 2, 5, 4, None, 7]
>>> sorted(l, key=lambda x: (x is None, x))
[1, 2, 3, 4, 5, 7, None]

This constructs a tuple for each element in the list, if the value is None the tuple with be (True, None), if the value is anything else it will be (False, x) (where x is the value). Since tuples are sorted item by item, this means that all non-None elements will come first (since False < True), and then be sorted by value.

17
votes

Try this:

sorted(l, key=lambda x: float('inf') if x is None else x)

Since infinity is larger than all integers, None will always be placed last.

-1
votes

I created a function that expands on the answer by Andrew Clark and the comment by tutuDajuju.

def sort(myList, reverse = False, sortNone = False):
    """Sorts a list that may or may not contain None.
    Special thanks to Andrew Clark and tutuDajuju for how to sort None on https://stackguides.com/questions/18411560/python-sort-list-with-none-at-the-end

    reverse (bool) - Determines if the list is sorted in ascending or descending order

    sortNone (bool) - Determines how None is sorted
        - If True: Will place None at the beginning of the list
        - If False: Will place None at the end of the list
        - If None: Will remove all instances of None from the list

    Example Input: sort([1, 3, 2, 5, 4, None, 7])
    Example Input: sort([1, 3, 2, 5, 4, None, 7], reverse = True)
    Example Input: sort([1, 3, 2, 5, 4, None, 7], reverse = True, sortNone = True)
    Example Input: sort([1, 3, 2, 5, 4, None, 7], sortNone = None)
    """

    return sorted(filter(lambda item: True if (sortNone != None) else (item != None), myList), 
        key = lambda item: (((item is None)     if (reverse) else (item is not None)) if (sortNone) else
                            ((item is not None) if (reverse) else (item is None)), item), 
        reverse = reverse)

Here is an example of how you can run it:

myList = [1, 3, 2, 5, 4, None, 7]
print(sort(myList))
print(sort(myList, reverse = True))
print(sort(myList, sortNone = True))
print(sort(myList, reverse = True, sortNone = True))
print(sort(myList, sortNone = None))
print(sort(myList, reverse = True, sortNone = None))