如何有效地比较Python中的大型列表?

时间:2017-01-27 07:56:23

标签: python algorithm list processing-efficiency

我试图找到9个字母的单词,当你将它们平均分成3个部分,并且混乱时,你会得到另外9个字母的单词。

for i in nineWordList:
    for j in nineWordList:
        if (i[3:5] + i[0:2] + i[6:8]) == j:
            correctWords.append(i)
        elif (i[3:5] + i[6:8] + i[0:2]) == j:
            correctWords.append(i)
        elif (i[0:2] + i[6:8] + i[3:5]) == j:
            correctWords.append(i)
        elif (i[6:8] + i[0:2] + i[3:5]) == j:
            correctWords.append(i)
        elif (i[6:8] + i[3:5] + i[0:2]) == j:
            correctWords.append(i)

我就是这样做的。唯一的问题是nineWordList长68,000个元素,这需要很长时间。我怎样才能改善这一点,使其更有效率?

2 个答案:

答案 0 :(得分:8)

使用set以避免在列表中的两个级别上循环:

nineWordSet = set(nineWordList)
for i in nineWordSet:
    if i[3:5] + i[0:2] + i[6:8] in nineWordSet:
        correctWords.append(i)
    elif i[3:5] + i[6:8] + i[0:2] in nineWordSet:
        correctWords.append(i)
    elif i[0:2] + i[6:8] + i[3:5] in nineWordSet:
        correctWords.append(i)
    elif i[6:8] + i[0:2] + i[3:5] in nineWordSet:
        correctWords.append(i)
    elif i[6:8] + i[3:5] + i[0:2] in nineWordSet:
        correctWords.append(i)

这仍然需要遍历所有68,000个条目(你显然无法避免),但在第一遍中,它会将列表转换为集合,因此使用in的成员资格测试可以在常量中进行时间。这为您提供线性时间复杂度,而不是嵌套循环所具有的二次时间复杂度。当然,额外的设置将需要更多的内存,但这应该不是问题。

顺便说一下。我相信你的切片是关闭的。 i[0:2]不会生成3个字母的单词(当您想要均匀分割9个字母的单词时):

>>> x = 'abcdefghi'
>>> x[0:2], x[3:5], x[6:8]
('ab', 'de', 'gh')

切片中的第二个索引始终是非包含性的,因此您需要将其增加一个:

>>> x[0:3], x[3:6], x[6:9]
('abc', 'def', 'ghi')

您还可以使用itertools.permutations生成那些可能的复句词来缩短您的条件。这样,您的支票可能会更好看:

import itertools
nineWordSet = set(nineWordList)

for word in nineWordSet:
    for perm in itertools.permutations((word[0:3], word[3:6], word[6:9])):
        # skip the original permutation
        if perm == word:
            continue

        elif perm in nineWordSet:
            correctWords.append(word)

            # stop checking for more permutations
            break

答案 1 :(得分:3)

将所有有效单词放在Python集中,然后循环遍历集合,以您描述的方式重新排列单词。对于每次重新排列,请检查它是否在集合中。

由于Python的集合为based on a hash table,因此查找会在O(1)(常量)时间内发生。对于每个单词的恒定重排次数,您的算法会在O(n)时间内运行,这比现在的O(n^2)算法要好得多。

修改后的代码如下所示:

nineWordSet = set(nineWordList)
for i in nineWordSet:
  if i[3:5] + i[0:2] + i[6:8] in nineWordSet:
    correctWords.append(i)
  elif i[3:5] + i[6:8] + i[0:2] in nineWordSet:
    correctWords.append(i)
  elif i[0:2] + i[6:8] + i[3:5] in nineWordSet:
    correctWords.append(i)
  elif i[6:8] + i[0:2] + i[3:5] in nineWordSet:
    correctWords.append(i)
  elif i[6:8] + i[3:5] + i[0:2] in nineWordSet:
    correctWords.append(i)

你之前的代码很慢,因为对于每个单词,你必须查看所有其他单词(技术上,其中一半是平均值)。这是你必须要看的大约2,312,000,000个单词;这就是O(n^2)的含义。在每个单词的新代码中,您只需查看一个明确定义的位置,因此您只需查看68,000个单词。这是hash tables的好处,通常可以在数据集上为您提供O(n)效果。