[英]Elegant way to remove contiguous repeated elements in a list?
我正在尋找一種干凈,Pythonic,從以下列表中消除的方法:
li = [0, 1, 2, 3, 3, 4, 3, 2, 2, 2, 1, 0, 0]
所有連續的重復元素 (運行長於一個數字),以獲得:
re = [0, 1, 2, 4, 3, 1]
但是雖然我有工作代碼,感覺不是Pythonic,我很確定必須有一種方法(可能是一些鮮為人知的itertools
函數?)以更加簡潔和優雅的方式實現我想要的東西。
這是一個基於Karl的版本,它不需要列表的副本( tmp
,切片和壓縮列表)。 對於大型列表, izip
明顯快於(Python 2) zip
。 chain
比切片稍慢,但不需要tmp
對象或列表的副本。 islice
加上制作一個tmp
要快一點,但需要更多的內存並且不那么優雅。
from itertools import izip, chain
[y for x, y, z in izip(chain((None, None), li),
chain((None,), li),
li) if x != y != z]
一個timeit
測試表明它是大約快兩倍,卡爾的還是我的最快groupby
版本短群體。
如果列表可以包含None
請確保使用None
以外的值(如object()
)。
如果您需要它來處理非序列的迭代器/可迭代,或者您的組很長,請使用此版本:
[key for key, group in groupby(li)
if (next(group) or True) and next(group, None) is None]
timeit
顯示它比1,000個項目組的其他版本快十倍。
早期,慢版本:
[key for key, group in groupby(li) if sum(1 for i in group) == 1]
[key for key, group in groupby(li) if len(tuple(group)) == 1]
如果組的大小很小,agf的答案是好的,但是如果連續有足夠的重復,那么在這些組中“加1”會更有效率
[key for key, group in groupby(li) if all(i==0 for i,j in enumerate(group)) ]
tmp = [object()] + li + [object()]
re = [y for x, y, z in zip(tmp[2:], tmp[1:-1], tmp[:-2]) if y != x and y != z]
其他解決方案使用各種itertools助手和理解,可能看起來更“pythonic”。 但是,我運行的快速計時測試表明這個生成器有點快:
_undef = object()
def itersingles(source):
cur = _undef
dup = True
for elem in source:
if dup:
if elem != cur:
cur = elem
dup = False
else:
if elem == cur:
dup = True
else:
yield cur
cur = elem
if not dup:
yield cur
source = [0, 1, 2, 3, 3, 4, 3, 2, 2, 2, 1, 0, 0]
result = list(itersingles(source))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.