簡體   English   中英

優雅的方法來刪除列表中連續的重復元素?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM