Python 需要帮助加快排列速度吗
这是我的工作代码,我正在努力寻找方法,让它更快地找到有效的单词,我在考虑可能为每个单词制作单独的词典列表,yall怎么想Python 需要帮助加快排列速度吗,python,permutation,Python,Permutation,这是我的工作代码,我正在努力寻找方法,让它更快地找到有效的单词,我在考虑可能为每个单词制作单独的词典列表,yall怎么想 import random import itertools file_name='words.txt' def load_words(): try: f=open(file_name,'r') str1=f.read() f.close() except: print('Problem op
import random
import itertools
file_name='words.txt'
def load_words():
try:
f=open(file_name,'r')
str1=f.read()
f.close()
except:
print('Problem opening the file',file_name)
list1=[]
list1=str1.split()
return(list1)
def is_valid(str1,list1):
valid=False
if str1 in list1:
valid=True
return valid
def generate(words,letters):
answers=[]
for length in range(2,len(letters)+1):
for x in itertools.permutations(letters,length):
word=''
for let in x:
word+=let
if is_valid(word.upper(),words):
answers.append(word)
print(word)
print(answers)
def main():
words=load_words()
letters = input('Enter your letters')
answers = generate(words,letters)
main()
将您的
列表1
更改为一组:
set1 = set(list1)
如果您经常进行测试并且列表很长,那么set1中的str1测试将比列表1中的str1测试快得多。首先,分析代码。这会告诉你慢的部分在哪里
第二,你可以考虑把单词列表转换成一个集合,它应该有一个更快的“in”运算符来检查单词是否存在。
第三,考虑简化代码以删除不必要的语句,如
def is_valid(str1,list1):
return str1 in list1
你到底想用这个做什么?看起来你已经有了一些有效单词的字典。为什么您要排列所有可以根据用户输入构建的单词组合 <>你需要考虑一下你的算法。您创建的每一个排列都在迭代字典中的每一个已知单词(列表1)。当你创建所有的单词排列时,你正在创建m!其中m是用户给出的字母数 你基本上有O(n*m!)。这对于像7这样的小数目的东西来说都是荒谬的巨大。通过使用一个集合,而不是一个列表,你可以把这个n项减少到一个常数,这会把你的算法变成O(m!),仍然太大如果要我猜这个算法在做什么,我会说你想知道你能从给出的字母中创建多少已知单词。你又没那么说,但让我们假设这就是你的意思 一个更快的算法是对字典中的每个单词进行迭代,看看是否可以通过从输入中选取字母来生成该单词。所以你只需要浏览一次字典。这样就不需要对输入进行置换。以下是算法:
user_input = input("Give me some words")
for word in list1:
current = user_input
found = True
for letter in word:
if letter in current:
current.remove( letter )
else
found = False
break;
if found:
answers.add( word )
print( answers )
很抱歉,我的python有点生疏,但希望您能理解。尝试将内部循环替换为:
for x in itertools.permutations(letters,length):
word = ''.join(x)
if word.upper() in words:
answers.append(word)
print(word)
如果你过于热衷于提高速度,而以降低可读性为代价,你可以尝试以下方法
def is_valid(str1,list1):
return str1 in list1
words=["BAD","CAB","BEC"]
def generate2(words,letters):
answers=[]
[[answers.append(''.join(x).upper()) for x in itertools.permutations(letters,length) if ''.join(x).upper() in words] for length in range(2,len(letters)+1)]
#print(answers)
return answers
。因此,将两个循环组合为一个理解。除此之外,声明
word=''
for let in x:
word+=let
if is_valid(word.upper(),words):
如果有效(''.join(x).upper,words)
或甚至'.join(x).upper在words
中,记住函数调用是昂贵的
我已经做了一个速度和外观的比较,它的运行速度快了50%
现在由你来决定
问题是你的算法基本上是O(n*m!),其中n是单词列表的大小,m是字母数。将单词列表更改为一个集合应该会使搜索记录时间,并将性能提高到O(log(n)*m!),这是其他人推荐的 然而,真正的性能增益将来自完全消除搜索中字母的排列。首先按字母顺序对单词表中每个单词的字母进行排序;它应该花费O(n*p log(p))时间,其中p是平均字长。然后在O(n*log(n))时间内按字母顺序对整个列表进行排序。还要跟踪原始单词,以便可以从排序单词列表中的字符串转到O(1)中的原始单词。接下来,按字母顺序对输入的字母进行排序,并在已排序的单词列表中搜索它们 上述算法中最慢的操作是对按字母顺序排序的字符串列表进行排序,即O(n Log(n))。搜索这样的列表是Log(n),结果是整个算法在O(n Log(n))时间内执行。它应该线性缩放到m,即输入的字母数
实现是留给读者的。如果您计划经常查找单词,您应该根据您的数据构建一个 下面是一个简单的例子。代码应该是非常自解释的,但是请询问是否有不清楚的地方
import pickle
class Tree:
def __init__(self):
self.letters = dict()
def add_words(self, words):
for word in words:
self.add_word(word)
def add_word(self, word):
chars = list(word.lower())
l = chars.pop(0)
try:
self.letters[l].add_word(chars)
except KeyError:
self.letters[l] = Letter(l)
self.letters[l].add_word(chars)
def is_word(self, word):
chars = list(word.lower())
l = chars.pop(0)
try:
return self.letters[l].is_word(chars)
except KeyError:
return False
class Letter:
def __init__(self, letter):
self.letter = letter
self.sub_letters = dict()
self.is_a_word = False
def add_word(self, word):
if len(word) == 0:
self.is_a_word = True
return
l = word.pop(0)
try:
self.sub_letters[l].add_word(word)
except KeyError:
self.sub_letters[l] = Letter(l)
self.sub_letters[l].add_word(word)
def is_word(self, word):
if len(word) == 0:
return self.is_a_word
l = word.pop(0)
try:
return self.sub_letters[l].is_word(word)
except KeyError:
return False
def get_dict(obj_file, dict_file):
try:
with open(obj_file, 'rb') as my_dict:
return pickle.load(my_dict)
except IOError:
my_tree = Tree()
with open(dict_file, 'rb') as in_file:
for word in in_file:
my_tree.add_word(word.strip())
with open(obj_file, 'wb') as outfile:
pickle.dump(my_tree, outfile, pickle.HIGHEST_PROTOCOL)
return my_tree
obj_file = 'mydict.pk'
dict_file = 'wordlist.txt'
my_tree = get_dict(obj_file, dict_file)
(有很多不同类型的树,这只是一个非常简单的例子)
构建树后,只需要len(word)
函数调用即可确定输入的单词是否有效。这是一个巨大的改进,如果单词列表中的单词,需要O(len(wordlist))
这种方法的缺点是,生成树可能需要一些时间。通过使用序列化Tree()
对象,您不必每次启动脚本时都构建树
我试图用一个单词列表(总共109582个单词)构建一棵树
通过对其计时,当取消勾选对象文件而不是从头构建dict时,执行时间减少了约50%
如果您只想检查排列,您应该首先更改
Tree()
的add\u word()
方法对字母进行排序。Tree.is\u word()
的输入参数当然也应该排序。谢谢你的评论,我觉得速度不快,如果你用输入的7个以上的字母运行程序,你会发现它的速度相当慢。作为一个集合,它比列表快几个数量级。@BrandonRutledge:不要依赖“感觉”来优化程序。使用类似“timeit”模块的方法来测试这些假设。()慢的部分是当有效单词为5个字符或更大时,我相信我根据eumiro的评论将其更改为一组,但我感觉速度没有变化,而且我不理解你的第三个陈述。第三个建议只是清理你的代码。列表1中的str1返回布尔值True或False,因此不需要If。。。返回True,否则返回False,因为If中的条件计算为True,所以只需返回它。消除它不会使您的算法更快,但它有助于减少代码大小并提高可读性。它实际上可能会改进executi
import pickle
class Tree:
def __init__(self):
self.letters = dict()
def add_words(self, words):
for word in words:
self.add_word(word)
def add_word(self, word):
chars = list(word.lower())
l = chars.pop(0)
try:
self.letters[l].add_word(chars)
except KeyError:
self.letters[l] = Letter(l)
self.letters[l].add_word(chars)
def is_word(self, word):
chars = list(word.lower())
l = chars.pop(0)
try:
return self.letters[l].is_word(chars)
except KeyError:
return False
class Letter:
def __init__(self, letter):
self.letter = letter
self.sub_letters = dict()
self.is_a_word = False
def add_word(self, word):
if len(word) == 0:
self.is_a_word = True
return
l = word.pop(0)
try:
self.sub_letters[l].add_word(word)
except KeyError:
self.sub_letters[l] = Letter(l)
self.sub_letters[l].add_word(word)
def is_word(self, word):
if len(word) == 0:
return self.is_a_word
l = word.pop(0)
try:
return self.sub_letters[l].is_word(word)
except KeyError:
return False
def get_dict(obj_file, dict_file):
try:
with open(obj_file, 'rb') as my_dict:
return pickle.load(my_dict)
except IOError:
my_tree = Tree()
with open(dict_file, 'rb') as in_file:
for word in in_file:
my_tree.add_word(word.strip())
with open(obj_file, 'wb') as outfile:
pickle.dump(my_tree, outfile, pickle.HIGHEST_PROTOCOL)
return my_tree
obj_file = 'mydict.pk'
dict_file = 'wordlist.txt'
my_tree = get_dict(obj_file, dict_file)