如何从列表末尾删除 None 的所有实例?
How to remove all instances of None from the end of a list?
Python 有一个名为 rstrip()
:
的字符串方法
>>> s = "hello world!!!"
>>> s.rstrip("!")
'hello world'
我想为 Python 列表实现类似的功能。也就是说,我想从列表末尾删除给定值的所有实例。在本例中,值为 None
.
这里有一些开始的例子:
[1, 2, 3, None]
[1, 2, 3, None, None, None]
[1, 2, 3, None, 4, 5]
[1, 2, 3, None, None, 4, 5, None, None]
我希望最终结果是:
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, None, 4, 5]
[1, 2, 3, None, None, 4, 5]
到目前为止,这是我的解决方案:
while l[-1] is None:
l.pop()
如果你想修改列表in-place,那么你的解决方案很好,只要确保处理列表为空的情况即可:
while l and l[-1] is None:
l.pop()
如果您想计算一个新列表,您可以将您的解决方案调整为:
def stripNone(l):
if not l:
return []
rlim = 0
for x in reversed(l):
if x is None:
rlim += 1
else:
break
return l[: len(l) - rlim]
还有itertools.dropwhile
,但是你要进行两次反转:
def stripNone(l):
return list(dropwhile(lambda x: x is None, l[::-1]))[::-1]
另外两个版本也适用于 None
-only 列表:
while None in l[-1:]:
l.pop()
for x in reversed(l):
if x is not None:
break
l.pop()
在 l = [None] * 10**3
上对一些解决方案进行基准测试:
83 us stripNone1
137 us stripNone2
60 us stripNone3
42 us stripNone3b
53 us stripNone4
34 us stripNone5
19 us stripNone6
请注意 stripNone2
和 stripNone6
有一个小缺陷:如果在跟踪 None
中有一个对象不是 None
但声称 equal None
,那么它将被删除。不过,这样的物体非常不寻常。也许有人实际上 想要 删除这样的对象。
基准代码:
def stripNone1(l):
while l and l[-1] is None:
l.pop()
def stripNone2(l):
while None in l[-1:]:
l.pop()
def stripNone3(l):
for x in reversed(l):
if x is not None:
break
l.pop()
def stripNone3b(l):
pop = l.pop
for x in reversed(l):
if x is not None:
break
pop()
def stripNone4(l):
for i, x in enumerate(reversed(l), 1):
if x is not None:
del l[-i:]
break
def stripNone5(l):
pop = l.pop
try:
while (last := pop()) is None:
pass
l.append(last)
except IndexError:
pass
def stripNone6(l):
while l:
chunk = l[-32:]
if chunk.count(None) < len(chunk):
while l[-1] is None:
l.pop()
break
del l[-32:]
from timeit import repeat
solutions = stripNone1, stripNone2, stripNone3, stripNone3b, stripNone4, stripNone5, stripNone6
for i in range(3):
print(f'Round {i+1}:')
for sol in solutions:
ls = [[42] * head + [None] * tail
for _ in range(5)
for head in range(0, 2001, 200)
for tail in range(0, 2001, 200)]
number = len(ls) // 5
ls = iter(ls)
time = min(repeat(lambda: sol(next(ls)), number=number)) / number
print(f'{int(time * 10**6):3d} us {sol.__name__}')
Python 有一个名为 rstrip()
:
>>> s = "hello world!!!"
>>> s.rstrip("!")
'hello world'
我想为 Python 列表实现类似的功能。也就是说,我想从列表末尾删除给定值的所有实例。在本例中,值为 None
.
这里有一些开始的例子:
[1, 2, 3, None]
[1, 2, 3, None, None, None]
[1, 2, 3, None, 4, 5]
[1, 2, 3, None, None, 4, 5, None, None]
我希望最终结果是:
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, None, 4, 5]
[1, 2, 3, None, None, 4, 5]
到目前为止,这是我的解决方案:
while l[-1] is None:
l.pop()
如果你想修改列表in-place,那么你的解决方案很好,只要确保处理列表为空的情况即可:
while l and l[-1] is None:
l.pop()
如果您想计算一个新列表,您可以将您的解决方案调整为:
def stripNone(l):
if not l:
return []
rlim = 0
for x in reversed(l):
if x is None:
rlim += 1
else:
break
return l[: len(l) - rlim]
还有itertools.dropwhile
,但是你要进行两次反转:
def stripNone(l):
return list(dropwhile(lambda x: x is None, l[::-1]))[::-1]
另外两个版本也适用于 None
-only 列表:
while None in l[-1:]:
l.pop()
for x in reversed(l):
if x is not None:
break
l.pop()
在 l = [None] * 10**3
上对一些解决方案进行基准测试:
83 us stripNone1
137 us stripNone2
60 us stripNone3
42 us stripNone3b
53 us stripNone4
34 us stripNone5
19 us stripNone6
请注意 stripNone2
和 stripNone6
有一个小缺陷:如果在跟踪 None
中有一个对象不是 None
但声称 equal None
,那么它将被删除。不过,这样的物体非常不寻常。也许有人实际上 想要 删除这样的对象。
基准代码:
def stripNone1(l):
while l and l[-1] is None:
l.pop()
def stripNone2(l):
while None in l[-1:]:
l.pop()
def stripNone3(l):
for x in reversed(l):
if x is not None:
break
l.pop()
def stripNone3b(l):
pop = l.pop
for x in reversed(l):
if x is not None:
break
pop()
def stripNone4(l):
for i, x in enumerate(reversed(l), 1):
if x is not None:
del l[-i:]
break
def stripNone5(l):
pop = l.pop
try:
while (last := pop()) is None:
pass
l.append(last)
except IndexError:
pass
def stripNone6(l):
while l:
chunk = l[-32:]
if chunk.count(None) < len(chunk):
while l[-1] is None:
l.pop()
break
del l[-32:]
from timeit import repeat
solutions = stripNone1, stripNone2, stripNone3, stripNone3b, stripNone4, stripNone5, stripNone6
for i in range(3):
print(f'Round {i+1}:')
for sol in solutions:
ls = [[42] * head + [None] * tail
for _ in range(5)
for head in range(0, 2001, 200)
for tail in range(0, 2001, 200)]
number = len(ls) // 5
ls = iter(ls)
time = min(repeat(lambda: sol(next(ls)), number=number)) / number
print(f'{int(time * 10**6):3d} us {sol.__name__}')