14

是否有一种优雅的 Pythonic 方法可以从列表中删除尾随的空元素?一种list.rstrip(None)。所以

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

应该导致

[1, 2, 3, None, 4]

我想这可以概括为删除任何特定值的尾随元素。

如果可能的话,我希望将其作为单行(可读)表达式完成

4

12 回答 12

21

如果您只想摆脱None值并留下零或其他虚假值,您可以这样做:

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

要删除所有虚假值(零、空字符串、空列表等),您可以执行以下操作:

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]
于 2012-04-05T19:41:48.337 回答
9

以下显式检查None元素:

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

可以概括如下:

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

您现在可以定义不同的函数f来检查其他条件。

于 2012-04-05T19:45:02.500 回答
4
def remove_trailing(l, remove_value=None):
    i = len(l)
    while i > 0 and l[i - 1] == remove_value:
        i -= 1
    return l[:i]
于 2012-04-05T19:51:51.610 回答
4

尝试这个

>>> x=[1, 2, 3, None, 4, None, None]
>>> while x[-1] is None:
    x.pop()
于 2012-04-05T19:45:46.670 回答
1

对于单线解决方案:

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]

如果你想重用它,这里有一个无点风格的定义:

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]
于 2012-04-05T19:51:20.970 回答
1

我从未接受过答案,因为我对所提供的解决方案并不满意。这是另一个我不完全满意的解决方案(1 行,没有库依赖项):

a = [1, 2, None, 3, None, None]
reduce(lambda l, e: [e]+l if l or e is not None else [], reversed(a), [])
于 2016-04-05T20:35:41.007 回答
0

如果您正在寻找单线,它可能是这样的:

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

请注意,它是二次的(在最坏的情况下)。

对于任何虚假值,它甚至更简单:

b = [x for n, x in enumerate(a) if any(a[n:])]
于 2012-04-05T19:57:40.033 回答
0

如果你真的需要牺牲可读性,我会这样做。

>>> 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]
于 2012-04-05T20:06:15.393 回答
0

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 iterable and predicate. See the source code for details.

于 2017-06-15T08:12:05.203 回答
-1

递归+切片呢?

>>> 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]

注意:我假设您不是在这里寻找计算效率最高的解决方案......

于 2012-04-05T21:30:10.617 回答
-1

这是另一个单线:

>>> 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]

这些东西很有趣!

编辑

我刚刚意识到列表理解是完全没有必要的。切片应该可以正常工作:

>>> l[:len("".join(map(lambda x: {None: " "}.get(x, "_"), l)).rstrip())] 
于 2012-04-05T20:04:18.327 回答
-1

关于什么:

[a[i] for i in range(len(a)) if a[i:] != [None] * (len(a) - i) ]
于 2015-02-05T12:38:29.357 回答