你並不需要在兩個list
秒值進行轉換,以set
S,只有一個。我認爲跳過不必要的轉換使其更具可讀性和優雅性。
所以,要麼:
set(a).intersection(b)
或者:
s = set(a)
any(e in s for e in b)
後者的優點是短路只要它找到一個匹配,更好地表達邏輯,並返回True
或False
而不是非虛假或錯誤的set
,但它是兩行而不是一個,如果那樣會困擾你。我不知道這個優點是否消除了將循環放入生成器表達式而不是C函數內部的代價。
績效結果與list
s這個小几乎是毫無意義的,所以讓我們試試這個:
In [373]: a=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [374]: b=[random.choice(string.ascii_lowercase) for _ in range(10000)]
In [375]: %timeit(set(a))
10000 loops, best of 3: 180 us per loop
In [376]: s=set(a) # since all versions need to do this
In [391]: %timeit(s & set(b))
1000000 loops, best of 3: 178 us per loop
In [392]: %timeit(s.intersection(b))
1000000 loops, best of 3: 247 us per loop
In [393]: %timeit(discard(e in s for e in b))
1000000 loops, best of 3: 550 ns per loop
In [394]: %timeit(any(e in s for e in b))
1000000 loops, best of 3: 749 ns per loop
In [395]: %timeit(any(e in a for e in b))
1000000 loops, best of 3: 1.42 us per loop
爲了把這些數字都在納秒的規模,加上早在set(a)
的成本是除了最後需要和比較來自三個Python版本的相同測試(Apple股票CPython 2.7.2,python.org CPython 3.3.0,Homebrew PyPy 1.9.0/2.7。2,所有的64位Mac版本):
CP272 CP330 PyPy
s & set(b) 358000 316000 180500
s.intersection(b) 427000 459000 180900
discard(genexp) 180550 157341 90094
any(genexp) 180749 157334 90208
any(list-genexp) 1420 686 960
現在我想到了這一點,這是完全合理的。很早就發生碰撞的機率非常高,因此將整個事件轉換爲集合的成本控制了一切。
這意味着我們需要一個新的測試,具有10000個唯一值。讓我們重複這個測試:
In [29]: a, b = list(range(10000)), list(range(10000))
In [30]: random.shuffle(a)
In [31]: random.shuffle(b)
CP272 CP330 PyPy
s & set(b) 1277000 1168000 1141000
s.intersection(b) 1165000 1117000 2520000
discard(genexp) 1699000 1271000 770000
any(genexp) 389800 344543 320807
any(list-genexp) 62000 10400 1520
這些更合理。而且他們仍然有道理。如果你比較相同的10000個元素隨機洗牌,你必須走多遠?不足以使set
的成本 - 使這兩個列表中的任何一個值得做,更不用說它們兩個!
所以,讓我們試着那裏有沒有一致的情況下:
In [43]: a=list(range(10000, 20000))
CP272 CP330 PyPy
s & set(b) 751000 770000 733000
s.intersection(b) 466000 530000 1920000
discard(genexp) 1246000 985000 749000
any(genexp) 1269000 966000 893000
any(list-genexp) 185000000 176000000 5870000
我不知道PyPy是怎麼做的最後一個如此之快,但除此之外,這裏沒有驚喜。
那麼,哪一個最好?很明顯,如果你期望碰到很多碰撞,你希望儘可能地避免做集合 - 但是如果你期望碰撞少,你至少要做一組。如果你不知道,我認爲最安全的賭注是any(genexp)
- 最壞的情況是它比最好的要差3倍,如果碰撞率很高,它會快很多。但你可以看看這些數字並親自查看。或者,當然,更好的辦法是將它們全部對照您期望遇到的實際測試數據。
是元素每個列表中是唯一的?如果是這樣,你可以簡單地使用'sets'來做到這一點。 – 2013-01-16 06:39:35
是的,列表中的元素是唯一的。 – Amyth
@Mike:等等...爲什麼你不能用set來做這件事,即使這些元素不唯一?您多次丟失元素存在的信息,但如果您關心的是元素存在,則不需要該信息。 (如果你這樣做,你總是可以使用'Counter'來代替'set'來保留它。) – abarnert