我正在寻找一种干净的,Pythonic的方法来消除以下列表:
li = [0, 1, 2, 3, 3, 4, 3, 2, 2, 2, 1, 0, 0]
所有连续的重复元素(运行时间超过一个数字)以获得:
re = [0, 1, 2, 4, 3, 1]
但是虽然我有工作代码,感觉不是Pythonic,我很确定必须有一条出路(可能是一些鲜为人知的itertools
函数?)来实现我想要的更简洁优雅的方式。
答案 0 :(得分:8)
这是一个基于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
测试显示它的速度大约是Karl的两倍,或者是短组的最快groupby
版本。
如果您的列表可以包含None
,请确保使用object()
以外的值(例如None
)。
如果您需要它来处理非序列的迭代器/迭代,或者您的组很长,请使用此版本:
[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]
答案 1 :(得分:4)
[key for key, group in groupby(li) if all(i==0 for i,j in enumerate(group)) ]
答案 2 :(得分:1)
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]
答案 3 :(得分:1)
其他解决方案使用各种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))