优雅的方法来删除列表中连续的重复元素?

时间:2011-10-03 23:54:54

标签: python list idioms python-2.x

我正在寻找一种干净的,Pythonic的方法来消除以下列表:

li = [0, 1, 2, 3, 3, 4, 3, 2, 2, 2, 1, 0, 0]

所有连续的重复元素(运行时间超过一个数字)以获得:

re = [0, 1, 2, 4, 3, 1]

但是虽然我有工作代码,感觉不是Pythonic,我很确定必须有一条出路(可能是一些鲜为人知的itertools函数?)来实现我想要的更简洁优雅的方式。

4 个答案:

答案 0 :(得分:8)

这是一个基于Karl的版本,它不需要列表的副本(tmp,切片和压缩列表)。对于大型列表,izip明显快于(Python 2)zipchain比切片稍慢,但不需要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)

如果组的大小很小,agf的答案是好的,但是如果连续有足够的重复,那么在这些组中“和1”将更有效

[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))