[英]Effectively search if part of a tuple exist in a list of tuples
我有一個元組列表,其中包含 6 位數字的元組,范圍從 01 到 99。例如:
tuple_list = {(01,02,03,04,05,06), (20,22,24,26,28,30), (02,03,04,05,06,99)}
對於此列表中的每個元組,我需要有效地搜索是否有任何其他元組至少有 5 個數字與之相同(不包括搜索到的數字)。 所以對於上面的例子,結果將是:
(01,02,03,04,05,06) -> (02,03,04,05,06,99)
(20,22,24,26,28,30) -> []
(02,03,04,05,06,99) -> (01,02,03,04,05,06)
列表本身很大,最多可以容納 1,000,000 條記錄。
我嘗試了一個一個地掃描列表的天真方法,但這具有O(n^2)
復雜度並且需要花費大量時間。
我考慮過可能使用dict
,但我找不到一種方法來搜索部分密鑰(如果我需要搜索確切的密鑰,它會工作得很好)。 也許需要某種后綴/前綴樹變體,但我似乎無法弄清楚。
任何幫助將不勝感激。
下面的代碼生成一個字典,其中鍵是一個 5 元組,值是包含這 5 個元素的所有元組的列表。
它在O(nm)中運行,其中n是元組列表的大小, m是每個元組的大小。 對於 6 元組,它在O(6n)中運行。 看下面的測試結果
def getCombos(tup):
"""
Produces all combinations of the tuple with 1 missing
element from the original
"""
combos = []
# sort the input tuple here if it's not already sorted
for i in range(0, len(tup)):
tupAsList = list(tup)
del tupAsList[i]
combos.append(tupAsList)
return combos
def getKey(combo):
"""
Creates a string key for a given combination
"""
strCombo = [str(i) for i in combo]
return ",".join(strCombo)
def findMatches(tuple_list):
"""
Returns dict of tuples that match
"""
matches = {}
for tup in tuple_list:
combos = getCombos(tup)
for combo in combos:
key = getKey(combo)
if key in matches:
matches[key].append(tup)
else:
matches[key] = [tup]
# filter out matches with less than 2 elements (optional)
matches = {k: v for k, v in matches.items() if len(v) > 1}
return matches
tuple_list = [(01,02,03,04,05,06), (20,22,24,26,28,30), (02,03,04,05,06,99)]
print(findMatches(tuple_list)) # output: {'2,3,4,5,6': [(1, 2, 3, 4, 5, 6), (2, 3, 4, 5, 6, 99)]}
我針對蠻力解決方案測試了這段代碼。 對於 1000 個元組,蠻力版本用了 5.5 秒,而這個解決方案用了 0.03 秒。 在這里查看回復
您可以通過遍歷值來重新排列 output,但這可能是不必要的,具體取決於您使用它的方式
此過程本質上是O(N^2) :您正在將 N 項與其他 N-1 項中的每一項進行比較。 這是一個距離度量,並且適用相同的理論結果(您可以在 Stack Overflow 和其他地方查找 all-to-all 距離算法)。 在大多數情況下,沒有足夠的信息從f(A, B)
和f(B, C)
中收集來預測f(A, C)
是大於還是小於 5。
首先,停止使用元組:它們與您的用例不匹配。 元組被索引,您不關心順序。 (01, 02, 03, 04, 05, 06) 和 (05, 99, 03, 02, 01, 06) 匹配五個數字,盡管只有兩個位置匹配。
使用自然數據類型:集合。 您的比較操作是len(A.intersection(B))
。 請注意,您可以將邏輯翻轉為直線距離度量: mismatch = len(AB)
並具有一點三角形邏輯,前提是所有集合的大小都相同(請參閱“三角形不等式”)。 例如,如果len(AB)
為 1,則匹配 5 個數字。 如果您還得到len(AC)
為 5,那么您就知道C與 B 有 4 個或 5 個數字不同,具體取決於匹配的數字。
考慮到你的集合的稀疏性(至少 99 中的 6 個數字),你可以在這里獲得少量的性能......但是開銷和額外的檢查可能會消耗你的積蓄,並且由此產生的算法仍然是O(N ^ 2 ) 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.