2017-09-29 69 views
0

問題:最Python化的方式來交叉引用兩個列表

我有一個比較複雜的交叉引用任務,我需要一個long列表(〜60萬項)和short列表(之間進行萬〜30萬項)。我試圖找到兩個列表之間的相似條目,並且每個唯一條目由三個不同的整數標識(稱爲它們int1,int2int3)。根據一個列表中的三個整數標識符,我想看看這三個整數是否在另一個列表中,並返回它們是哪一個。

嘗試

首先我拉上在long列表中的每個三整數元組成稱爲a陣列。同樣,我拉上在short列表中的每個三INT元組到名爲b數組:

a = [(int1,int2,int3),...] # 600,000 entries 
b = [(int1,int2,int3),...] # 300,000 entries 

然後,我通過a每個條目重複,看它是否是b。如果是的,我所附相應元組到外循環的陣列稱爲c

c= [] 
for i in range(0,len(a),1): 
    if a[i] in b: 
     c.append(a[i]) 

迭代是(不奇怪)非常緩慢。我猜Python每次迭代(〜300,000次!)都必須檢查ba[i],並且它的迭代次數是600,000次。它已經花了一個多小時了,但還沒有完成,所以我知道我應該優化一些東西。

我的問題是:什麼是執行此交叉引用最Pythonic或最快的方法?

回答

9

您可以使用集:

c = set(b).intersection(a) 

我選擇b轉換爲一組,因爲它是兩個名單中較短的一個。使用intersection()不需要首先將列表a轉換爲集合。

你也可以這樣做:

c = set(a) & set(b) 

然而,這兩個列表需要轉換爲鍵入set第一。請參閱time complexity

1

Pandas解決方案:

a = [(1,2,3),(4,5,6),(4,5,8),(1,2,8) ] 
b = [(1,2,3),(0,3,7),(4,5,8)] 
df1 = pd.DataFrame(a) 
print (df1) 
    0 1 2 
0 1 2 3 
1 4 5 6 
2 4 5 8 
3 1 2 8 

df2 = pd.DataFrame(b) 
print (df2) 
    0 1 2 
0 1 2 3 
1 0 3 7 
2 4 5 8 

df = pd.merge(df1, df2) 
print (df) 
    0 1 2 
0 1 2 3 
1 4 5 8 

pythonset氏液:

c = list(set(b).intersection(set(a))) 
print (c) 
[(4, 5, 8), (1, 2, 3)] 
0

另一個有趣的方式來做到這一點:

from itertools import compress 
list(compress(b, map(lambda x: x in a, b))) 

與其他一個:

filter(lambda x: x in a, b) 
+1

你會可能會更好使用''過濾器代替地圖的'()()'和擺脫'compress()'。 a中的x仍然很慢;考慮首先將'a'轉換爲集合。 – mhawke

+0

絕對正確。 –