3 回答

TA貢獻(xiàn)1803條經(jīng)驗(yàn) 獲得超3個(gè)贊
正如Raymond所指出的那樣,在OrderedDict
用C語言實(shí)現(xiàn)的python 3.5+中,列表理解方法會(huì)慢于OrderedDict
(除非你實(shí)際上需要最后的列表 - 即便如此,只有當(dāng)輸入非常短時(shí))。所以3.5+的最佳解決方案是OrderedDict
。
more_itertools
library(pip install more_itertools
)包含一個(gè)unique_everseen
用于解決此問題的函數(shù),而列表推導(dǎo)中沒有任何不可讀(not seen.add
)的突變。這也是最快的解決方案:
>>> from more_itertools import unique_everseen>>> items = [1, 2, 0, 1, 3, 2]>>> list(unique_everseen(items))[1, 2, 0, 3]
只需一個(gè)簡單的庫導(dǎo)入,沒有黑客攻擊。這來自itertools配方的實(shí)現(xiàn),unique_everseen
如下所示:
def unique_everseen(iterable, key=None): "List unique elements, preserving order. Remember all elements ever seen." # unique_everseen('AAAABBBCCDAABBB') --> A B C D # unique_everseen('ABBCcAD', str.lower) --> A B C D seen = set() seen_add = seen.add if key is None: for element in filterfalse(seen.__contains__, iterable): seen_add(element) yield element else: for element in iterable: k = key(element) if k not in seen: seen_add(k) yield element
在Python中2.7+
,可接受的常用習(xí)慣用法(雖然可以工作但不是針對速度進(jìn)行優(yōu)化,我現(xiàn)在會(huì)使用unique_everseen
)用于此用途collections.OrderedDict
:
運(yùn)行時(shí)間:O(N)
>>> from collections import OrderedDict>>> items = [1, 2, 0, 1, 3, 2]>>> list(OrderedDict.fromkeys(items))[1, 2, 0, 3]
這看起來比以下更好:
seen = set()[x for x in seq if x not in seen and not seen.add(x)]
并沒有利用丑陋的黑客:
not seen.add(x)
它依賴于set.add
一個(gè)就地方法的事實(shí),它始終返回None
所以not None
求值True
。
但請注意,雖然hack解決方案具有相同的運(yùn)行時(shí)復(fù)雜度O(N),但它的原始速度更快。

TA貢獻(xiàn)1844條經(jīng)驗(yàn) 獲得超8個(gè)贊
在Python 2.7中,從迭代中刪除重復(fù)項(xiàng)同時(shí)保持原始順序的新方法是:
>>> from collections import OrderedDict>>> list(OrderedDict.fromkeys('abracadabra'))['a', 'b', 'r', 'c', 'd']
在Python 3.5中,OrderedDict有一個(gè)C實(shí)現(xiàn)。我的時(shí)間表明,現(xiàn)在這是Python 3.5的各種方法中最快和最短的。
在Python 3.6中,常規(guī)字典變得有序且緊湊。(此功能適用于CPython和PyPy,但在其他實(shí)現(xiàn)中可能不存在)。這為我們提供了一種新的最快的扣除方式,同時(shí)保留了訂單:
>>> list(dict.fromkeys('abracadabra'))['a', 'b', 'r', 'c', 'd']
在Python 3.7中,保證常規(guī)字典在所有實(shí)現(xiàn)中都有序。 因此,最短和最快的解決方案是:
>>> list(dict.fromkeys('abracadabra'))['a', 'b', 'r', 'c', 'd']
對@max的響應(yīng):一旦你移動(dòng)到3.6或3.7并使用常規(guī)字典而不是OrderedDict,你就無法以任何其他方式擊敗性能。字典很密集,很容易轉(zhuǎn)換成幾乎沒有開銷的列表。目標(biāo)列表預(yù)先調(diào)整為len(d),其保存列表推導(dǎo)中出現(xiàn)的所有調(diào)整大小。此外,由于內(nèi)部密鑰列表是密集的,因此復(fù)制指針幾乎快速作為列表副本。
添加回答
舉報(bào)