How do I remove 'None' items from the end of a list in Python

Question:

A have a list that might contain items that are None. I would like to remove these items, but only if they appear at the end of the list, so:

[None, "Hello", None, "World", None, None]
# Would become:
[None, "Hello", None, "World"]

I have written a function, but I’m not sure this is the right way to go about it in python?:

def shrink(lst):
    # Start from the end of the list.
    i = len(lst) -1
    while i >= 0:
        if lst[i] is None:
            # Remove the item if it is None.
            lst.pop(i)
        else:
            # We want to preserve 'None' items in the middle of the list, so stop as soon as we hit something not None.
            break
        # Move through the list backwards.
        i -= 1

Also a list comprehension as an alternative, but this seems inefficient and no more readable?:

myList = [x for index, x in enumerate(myList) if x is not None or myList[index +1:] != [None] * (len(myList[index +1:]))]

What it the pythonic way to remove items that are ‘None’ from the end of a list?

Asked By: leeman

||

Answers:

Discarding from the end of a list is efficient.

while lst[-1] is None:
    del lst[-1]

Add a safeguard for IndexError: pop from empty list if necessary. It depends on your specific application whether proceeding with an empty list should be considered normal or an error condition.

while lst and lst[-1] is None:
    del lst[-1]
Answered By: wim

Easiest way would probably be what you did. Here’s a conceptually simpler implementation of that:

def shrink(lst):
    copy_lst = lst[:]  # don't modify the original
    while copy_lst[-1] is None:  # you can get the last element in 1 step with index -1
        copy_list.pop()
    return copy_lst

As of python 3.8, and the walrus operator, it would be possible to do in a list comprehension, but this is a hacky solution and you shouldn’t use it:

def shrink(lst):
    at_end = True
    return reversed([(at_end := e is None and at_end, e)[1] for e in reversed(lst) if not at_end])
Answered By: Green Cloak Guy

If you don’t want to modify the list, you can just find the first index from the right that isn’t None and slice to it:

def shrink(l):
    for i in range(len(l) - 1, -1, -1):
        if l[i] is not None:
            return l[:i + 1]
    return l[:0]

If you do want to modify the list in-place, you can just delete the slice:

def shrink(l):
    for i in range(len(l) - 1, -1, -1):
        if l[i] is not None:
            break
    else:
        i = -1
    del l[i + 1:]
Answered By: Artyer
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.