Removing trailing blank items in a list

Is there an elegant Python way to remove trailing empty elements from a list? A sort of list.rstrip(None) . So

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

should lead to

 [1, 2, 3, None, 4] 

I believe this can be generalized by removing the finite elements of any particular value.

If possible, I would like to make it as a single-line (readable) expression

+10
source share
12 answers

If you want to get rid of only None values ​​and leave zeros or other false values, you can do the following:

 while my_list and my_list[-1] is None: my_list.pop() 

To remove all false values ​​(zeros, empty lines, empty lists, etc.), you can do the following:

 my_list = [1, 2, 3, None, 4, None, None] while not my_list[-1]: my_list.pop() print(my_list) # [1, 2, 3, None, 4] 
+18
source

The following explicitly check for None elements:

 while l and l[-1] is None: l.pop() 

It can be summarized as follows:

 f = lambda x: x is None while l and f(l[-1]): l.pop() 

Now you can define different functions for f to check other conditions.

+9
source

try it

 >>> x=[1, 2, 3, None, 4, None, None] >>> while x[-1] is None: x.pop() 
+4
source
 def remove_trailing(l, remove_value=None): i = len(l) while i > 0 and l[i - 1] == remove_value: i -= 1 return l[:i] 
+4
source

I never accepted the answer, because I was not very pleased with the proposed solutions. Here's another solution (1 line and no dependencies in the library) that I'm not quite happy with:

 a = [1, 2, None, 3, None, None] reduce(lambda l, e: [e]+l if l or e is not None else [], reversed(a), []) 
+1
source

For a single line solution:

 In [30]: from itertools import dropwhile In [31]: list(reversed(tuple(dropwhile(lambda x: x is None, reversed([1, 2, 3, None, 4, None, None]))))) Out[31]: [1, 2, 3, None, 4] 

If you want to reuse it, here is a point-free definition:

 In [36]: from functional import compose, partial In [37]: varargs = lambda *args: args In [38]: compose_mult = compose(partial(reduce, compose),varargs) # compose which takes variable number of arguments. Innermost function to the right. In [39]: compose_mult(list, reversed, tuple, partial(dropwhile, lambda x: x is None), reversed)([1, 2, 3, None, 4, None, None]) Out[39]: [1, 2, 3, None, 4] 
0
source

If you really need to compromise readability, here's what I will do.

 >>> from itertools import takewhile >>> l=[1,2,3,None,4,5,None,None] >>> l[:-len(list(takewhile(lambda x: x==None, reversed(l))))] [1,2,3,None,4,5] 
0
source

If you are looking for a one-liner, it could be like this:

 a = [1, 2, 3, None, 4, None, None] b = [x for n, x in enumerate(a) if any(y is not None for y in a[n:])] print b 

Note that it is quadratic (in the worst case).

For any false value, this is even simpler:

 b = [x for n, x in enumerate(a) if any(a[n:])] 
0
source

Here's another one-liner:

 >>> l = [1, 2, 3, None, 4, None, None] >>> [l[i] for i in range(len("".join(map(lambda x: {None: " "}.get(x, "_"), l)).rstrip()))] [1, 2, 3, None, 4] 

It's fun!

EDIT

I just realized that understanding the list is completely unnecessary. Slicing should work fine:

 >>> l[:len("".join(map(lambda x: {None: " "}.get(x, "_"), l)).rstrip())] 
-one
source

How about recursion + slicing?

 >>> rstrip = lambda x, elts=(None,): rstrip(x[:-1], elts) if x and x[-1] in elts else x >>> rstrip([1, 2, 3, None]) [1, 2, 3] >>> rstrip([1, 2, 3, None], (None, 3)) [1, 2] 

Note. I assume that you are not looking for the most efficient computing solution here ...

-one
source

What about:

 [a[i] for i in range(len(a)) if a[i:] != [None] * (len(a) - i) ] 
-one
source

The more_itertools project implements rstrip for any iterable:

 iterable = [1, 2, 3, None, 4, None, None] list(mit.rstrip(iterable, lambda x: x in {None})) # [1, 2, 3, None, 4] 

more_itertools.rstrip accepts an iterative and predicate. See the source code for more details.

-one
source

All Articles