如何有效地比较 Python 中的大型列表?
How to efficiently compare large lists in Python?
我正在尝试找到 9 个字母的单词,当你平均分成 3 个部分,然后混在一起,你会得到另一个九个字母的单词。
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 个元素,这需要很长时间。我该如何改进它,使其更有效率?
使用 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')
切片中的第二个索引始终是 non-inclusive 因此您需要将其增加一个:
>>> 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
将所有有效单词放入一个 Python 集合中,然后循环遍历该集合,按照您描述的方式重新排列单词。对于每个重排,检查它是否在集合中。
由于 Python 的集合是 based on a hash table,因此 look-ups 发生在 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)
的意思。在每个单词的新代码中,您只需查看一个 well-defined 位置,因此您只需查看 68,000 个单词。这就是 hash tables 的好处,它通常可以让您在数据集上获得 O(n)
性能。
我正在尝试找到 9 个字母的单词,当你平均分成 3 个部分,然后混在一起,你会得到另一个九个字母的单词。
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 个元素,这需要很长时间。我该如何改进它,使其更有效率?
使用 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')
切片中的第二个索引始终是 non-inclusive 因此您需要将其增加一个:
>>> 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
将所有有效单词放入一个 Python 集合中,然后循环遍历该集合,按照您描述的方式重新排列单词。对于每个重排,检查它是否在集合中。
由于 Python 的集合是 based on a hash table,因此 look-ups 发生在 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)
的意思。在每个单词的新代码中,您只需查看一个 well-defined 位置,因此您只需查看 68,000 个单词。这就是 hash tables 的好处,它通常可以让您在数据集上获得 O(n)
性能。