[英]list intersection algorithm implementation only using python lists (not sets)
我一直在嘗試用python寫下一個列表交集算法,該算法負責重復。 我是python和編程的新手,如果聽起來效率不高,請原諒我,但我無能為力。 這里,L1和L2是所討論的兩個列表,L是交集。
我100%肯定這不是Mathematica中用於評估列表交集的算法,但是我真的無法提出更有效的方法。 我不想在此過程中修改L1和L2,因此我將交集重新添加到兩個列表中。 有任何想法嗎? 我不想利用列表以外的任何內置函數/數據類型,因此沒有導入集或類似的東西。 就我而言,這是算法和實現練習,而不是編程練習。
遍歷L1
所有內容,每次遍歷L2
所有內容,都將花費二次時間。 改進的唯一方法是避免迭代所有L2
。 (存在類似的問題,最后從L
刪除重復項。)
如果對L2
(和L
)使用set
,那么in L2
步驟中的每個步當然都是恆定時間,因此整個算法是線性的。 而且,您始終可以構建自己的哈希表實現,而不是使用set
。 但這是很多工作。
使用二叉搜索樹,甚至只是一個排序列表和binary_find
函數,都可以在O(N log N)中進行。 而且, binary_find
更容易編寫自己。 所以:
S2 = sorted(L2)
L = [element for element in L1 if binary_find(element, S2)]
S = remove_adjacent(sorted(L))
或者,更簡單地說,也對L1進行排序,那么您就不需要remove_adjacent
:
S1, S2 = sorted(L1), sorted(L2)
L = []
for element in S1:
if binary_find(element, S2) and (not L or L[-1] != element):
L.append(element)
無論哪種方式,這都是O(N log N),其中N是較長列表的長度。 相比之下,原始答案是O(N ^ 2),其他答案是O(N ^ 3)。 當然,它有點復雜,但是仍然很容易理解。
您需要編寫binary_find
(如果適用,還需要編寫remove_adjacent
),因為我假設即使您不想使用額外的內置函數,也不想使用stdlib中的內容。 但這真的很容易。 例如:
def binary_find(element, seq):
low, high = 0, len(seq),
while low != high:
mid = (low + high) // 2
if seq[mid] == element:
return True
elif seq[mid] < element:
low = mid+1
else:
high = mid
return False
def remove_adjacent(seq):
ret = []
last = object()
for element in seq:
if element != last:
ret.append(element)
last = element
return ret
如果您甚至不想使用sorted
或list.sort
,也可以很容易地編寫自己的排序。
這是一個更快的解決方案:
def intersect_sorted(a1, a2):
"""Yields the intersection of sorted lists a1 and a2, without deduplication.
Execution time is O(min(lo + hi, lo * log(hi))), where lo == min(len(a1),
len(a2)) and hi == max(len(a1), len(a2)). It can be faster depending on
the data.
"""
import bisect, math
s1, s2 = len(a1), len(a2)
i1 = i2 = 0
if s1 and s1 + s2 > min(s1, s2) * math.log(max(s1, s2)) * 1.4426950408889634:
bi = bisect.bisect_left
while i1 < s1 and i2 < s2:
v1, v2 = a1[i1], a2[i2]
if v1 == v2:
yield v1
i1 += 1
i2 += 1
elif v1 < v2:
i1 = bi(a1, v2, i1)
else:
i2 = bi(a2, v1, i2)
else: # The linear solution is faster.
while i1 < s1 and i2 < s2:
v1, v2 = a1[i1], a2[i2]
if v1 == v2:
yield v1
i1 += 1
i2 += 1
elif v1 < v2:
i1 += 1
else:
i2 += 1
它以O(min(n + m, n * log(m)))
時間運行,其中n是長度的最小值,而m是最大值。 它同時遍歷兩個列表,並在開頭盡可能地跳過盡可能多的元素。
可在此處進行分析: http : //ptspts.blogspot.ch/2015/11/how-to-compute-intersection-of-two.html
怎么樣:
效率不是特別高,但是在代碼中看起來像這樣(重復說明):
>>> L1 = [1,2,3,3,4]
>>> L2 = [2,3,4,4,5]
>>> L = list()
>>> for v1 in L1:
for v2 in L2:
if v1 == v2 and v1 not in L:
L.append(v1)
>>> L
[2,3,4]
您只需通過檢查元素是否已在L中,然后將其添加到L中來避免從L1和L2中刪除。 然后,L1和L2中是否存在重復都沒關系。
編輯:我讀錯了標題,並瀏覽了內置部分。 我還是要把它留在這里,可能會幫助別人。
您可以使用set
類型來實現。
>>> a = [1,2,3,4]
>>> b = [3,4,5,6]
>>> c = list(set(a) & set(b))
>>> c
[3, 4]
if element in list2
)並且不在您的臨時列表中(相同的語法) 我為發布解決方案感到難過,但說實話,它比我的文字可讀性強:
def intersection(l1, l2):
temp = []
for item in l1:
if item in l2 and item not in temp:
temp.append(item)
return temp
以下是一種Python高效的方法,用於計算兩個列表的交集以保留順序並消除重復項:
L1 = [1,2,3,3,4,4,4,5,6]
L2 = [2,4,6]
aux = set()
L = [x for x in L1 if x in L2 and not (x in aux or aux.add(x)) ]
該解決方案使用集合“ aux”來存儲已經添加到結果列表中的元素。
請注意,您不需要“導入”集合,因為它們是Python中的本機數據類型。 但是,如果您堅持不使用集合,則可以選擇使用列表的效率較低的版本:
L1 = [1,2,3,3,4,4,4,5,6]
L2 = [2,4,6]
aux = []
L = [x for x in L1 if x in L2 and not (x in aux or aux.append(x)) ]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.