繁体   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