簡體   English   中英

有效地搜索元組的一部分是否存在於元組列表中

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM