Удаление конечных пустых элементов в списке
Есть ли элегантный питонский способ удаления конечных пустых элементов из списка? Этакий list.rstrip(None)
. Так
[1, 2, 3, None, 4, None, None]
должно привести к
[1, 2, 3, None, 4]
Я полагаю, это можно обобщить, удалив конечные элементы любого конкретного значения.
Если возможно, я бы хотел сделать это как однострочное (читабельное) выражение
Ответы
Ответ 1
Если вы хотите избавиться только от значений 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]
Ответ 2
Следующие явно проверяют элементы 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
для проверки других условий.
Ответ 3
Попробуйте это
>>> x=[1, 2, 3, None, 4, None, None]
>>> while x[-1] is None:
x.pop()
Ответ 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]
Ответ 5
Я никогда не принимал ответа, потому что я был не очень доволен предлагаемыми решениями. Здесь другое решение (1 строка и никакие зависимости в библиотеке), что я не совсем доволен:
a = [1, 2, None, 3, None, None]
reduce(lambda l, e: [e]+l if l or e is not None else [], reversed(a), [])
Ответ 6
Для однострочного решения:
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]
Если вы хотите его повторно использовать, здесь определение в стиле point-free:
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]
Ответ 7
Если вам действительно нужно компрометировать читаемость, вот что я сделаю.
>>> 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]
Ответ 8
Если вы ищете однострочник, это может быть так:
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:])]
Ответ 9
Здесь еще один однострочный:
>>> 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())]
Ответ 10
Как насчет рекурсии + нарезки?
>>> 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]
Примечание. Я предполагаю, что вы не ищете наиболее эффективное вычислительное решение здесь...
Ответ 11
Как насчет:
[a[i] for i in range(len(a)) if a[i:] != [None] * (len(a) - i) ]
Ответ 12
Проект more_itertools
реализует rstrip
для любого итерабельного:
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
принимает итеративный и предикат. Подробнее см. исходный код.