簡體   English   中英

在 Python 中使用條件匹配將列表鏈接在一起

[英]Chaining Lists Together In Python With Condition Matching

前提:

我有兩個單詞的短語列表,我需要嘗試將它們菊花鏈在一起。

我有十二個列表,每個列表中有數千個配對條目,我需要通過列表找到所有可能的條目鏈。

列表相對於彼此的順序是固定的——list3 跟隨 list2 跟隨 list1,等等。我有一個解決方案,但它絕對是老派的並且不是很 Pythonic——並且它需要永遠運行。 我上次運行花了 3 小時 40 分鍾,這是完全行不通的。

因此,我正在尋找任何更有效的解決方案,並且(希望)將流程加快到可管理的程度。

輸入格式:

輸入數據被格式化為二維列表,如下所示:

l1 = [ ['SHORT', 'FILM'], ['LEASE', 'BACK'], ['SHELF', 'LIFE'], ['HOLDS', 'FAST'], ... ]
l2 = [ ['BOAT', 'DECK'], ['FAST', 'FOOD'], ['FILM', 'PROP'], ['CHOW', 'LINE'], ... ]
l3 = [ ['FOOD', 'DRIVE'], ['PROP', 'PLANE'], ['GOAL', 'LINES'], ['WRAP', 'PARTY'], ... ]
.
.
.
l12 = [ [ ...

輸出:

我需要找到與列表中每對的第二個單詞與下一個列表中的第一個單詞相匹配的所有可能的單詞鏈,等等,菊花鏈一直貫穿。

我的代碼(為簡潔起見僅縮短為三個列表)如下所示:

l1 = [['SHORT', 'FILM'], ['LEASE', 'BACK'], ['SHELF', 'LIFE'], ['HOLDS', 'FAST']]
l2 = [['BOAT', 'DECK'], ['FAST', 'FOOD'], ['FILM', 'PROP'], ['CHOW', 'LINE']]
l3 = [['FOOD', 'DRIVE'], ['PROP', 'PLANE'], ['GOAL', 'LINES'], ['WRAP', 'PARTY']]

ans = []

for i in range(len(l1)):
        for j in range(len(l2)):
                if  l1[i][1] == l2[j][0]:
                        for k in range(len(l3)):
                                if l2[j][1] == l3[k][0]:
                                        item = [l1[i][0], l1[i][1], l2[j][1], l3[k][1]]
                                        ans.append(item)

print(ans)

這給出了以下輸出:

[['SHORT', 'FILM', 'PROP', 'PLANE'], ['HOLDS', 'FAST', 'FOOD', 'DRIVE']]

關於更有效和更快(!)的方法有什么建議嗎?

附加信息和限制

我發現了更多關於此的詳細信息,這些詳細信息提供了將更改代碼的附加約束。 首先,實際上並沒有 12 個列表,有 3 個列表重復(按順序)4 次:list1、list2、list3、list1、list2、list3 等。

此外,列表需要在末尾“圈”回,以便 list12 中的第二個單詞(與 list3 相同)匹配 list1 中的第一個單詞(l12[j][1] == l1[k][0])

例如,為了鏈:

HORSE BACK FLIP PHONE HOME RUNS SHORT FILM PROP PLANE RIDE HIGH

要成為有效的解決方案, HIGH HORSE必須在 list12/list3 上。

此外,由於三個列表重復四次並繞圈,因此四個循環

HORSE BACK FLIP PHONE HOME RUNS SHORT FILM PROP PLANE RIDE HIGH
PHONE HOME RUNS SHORT FILM PROP PLANE RIDE HIGH HORSE BACK FLIP
SHORT FILM PROP PLANE RIDE HIGH HORSE BACK FLIP PHONE HOME RUNS
PLANE RIDE HIGH HORSE BACK FLIP PHONE HOME RUNS SHORT FILM PROP

被認為是同一個詞循環,應該刪除欺騙。

我使用的代碼片段是:

for i in range(len(list1)):
  for j in range(len(list2)):
    if  list1[i][1] == list2[j][0]:
      for k in range(len(list3)):
        if list2[j][1] == list3[k][0]:
          for l in range(len(list1)):
            if list3[k][1] == list1[l][0]:
              for m in range(len(list2)):
                if list1[l][1] == list2[m][0]:
                  for n in range(len(list3)):
                    if list2[m][1] == list3[n][0]:
                      for o in range(len(list1)):
                        if list3[n][1] == list1[o][0]:
                          for p in range(len(list2)):
                            if list1[o][1] == list2[p][0]:
                              for q in range(len(list3)):
                                if list2[p][1] == list3[q][0]:
                                  for r in range(len(list1)):
                                    if list3[q][1] == list1[r][0]:
                                      for s in range(len(list2)):
                                        if list1[r][1] == list2[s][0]:
                                          for t in range(len(list3)):
                                            if list2[s][1] == list3[t][0] and list3[t][1] == list1[i][0]:
                                              item = [list1[i][0], list1[i][1], list2[j][1], list3[k][1], list1[l][1], list2[m][1], list3[n][1], list1[o][1], list2[p][1], list3[q][1], list1[r][1], list2[s][1]]
                                              ans.append(item)

這給了我所有的循環,但不會刪除重復項。 而且......需要幾個小時才能完成。

有什么建議?

您希望從每個列表構建字典,以便可以對每個連接進行快速查找,而不必遍歷整個下一個列表以查找匹配項。 這應該可以為您節省大量時間。 我對大 O 表示法沒有做太多,但我認為這將 O(N^2) 問題變成了 O(N) 問題。

以下是針對您提供的縮減示例執行此操作的方法。 它應該同樣適用於您的 12 個長列表(實際上更好):

l1 = [['SHORT', 'FILM'], ['LEASE', 'BACK'], ['SHELF', 'LIFE'], ['HOLDS', 'FAST']]
l2 = [['BOAT', 'DECK'], ['FAST', 'FOOD'], ['FILM', 'PROP'], ['CHOW', 'LINE']]
l3 = [['FOOD', 'DRIVE'], ['PROP', 'PLANE'], ['GOAL', 'LINES'], ['WRAP', 'PARTY']]

# Define a list of our lists so we can iterate over them
lists = [l1, l2, l3]

# For each list except the first one, create an equivalent dictionary where the first value
# in each list entry is a key, and the second value is the corresponding value for that key.
dicts = [{e[0]:e[1] for e in l} for l in lists[1:]]

# Attempt to find a full chain for one of the pairs in list #1
def do_one_chain(pair):
    chain = []
    chain.extend(pair)
    for d in dicts:
        if pair[1] not in d:
            return None
        pair = (pair[1], d[pair[1]])
        chain.append(pair[1])
    return chain

# Iterate over our first list...
ans = []
for pair in l1:
    # Apply our search function to a pair from list #1
    r = do_one_chain(pair)
    # If a chain was found, add it to the answer list
    if r:
        ans.append(r)

# Print the found chains
print(ans)

結果:

[['SHORT', 'FILM', 'PROP', 'PLANE'], ['HOLDS', 'FAST', 'FOOD', 'DRIVE']]

這樣做的好處是,該解決方案不僅效率更高,而且更清潔和緊湊。 當您添加更多級別時,任何代碼都不會更改。 您只需將新級別添加到lists列表中。 我知道這就是你要找的東西,害怕不得不將那些嵌套的if語句擴展到 12 個級別,對吧?

請報告此算法在您的完整數據集上運行所需的時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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