每日编码问题11中的问题,转载如下:
实施自动完成系统。也就是说,给定一个查询字符串s和一组所有可能的查询字符串,请返回该集中所有以s为前缀的字符串。
例如,给定查询字符串de和字符串集[dog,deer,deal],返回[deer,deal]。
提示:尝试将字典预处理为更有效的数据结构,以加快查询速度。
我想出了一个可行的(希望)解决方案,但是在这样做的过程中,我遇到了一些我无法理解的东西。问题如下。
def autocomplete(word):
words = []
## Set up word import wordDict
with open('11_word_list.txt','r') as f:
for line in f:
words += line.split()
## Optional: Filter out words with same first alphabet of search word
## Then ensure that remaining words also are at least as long as search word
words = filter(lambda x: x[0] == word[0], words)
words = filter(lambda x: len(x) >= len(word), words)
## Strictly speaking, this is the only required line that can still
## make this solution work
words = filter(lambda x: x.startswith(word), words)
####################
## Works in progress
####################
##Suppose that the content of words[] are already as long as, or longer than
##the search term, how come only Option B seems to work, but when shortened into
##Option A as a more generic form, it does not work?
##
##Put simply, it seems words[] is not updated after every run of the for loop??
## Option A
## for i in range(1,len(word)):
## words = filter(lambda x: x[i] == word[i], words)
## Option B
## words = filter(lambda x: x[1] == word[1], words)
## words = filter(lambda x: x[2] == word[2], words)
## words = filter(lambda x: x[3] == word[3], words)
return list(words)
在注释区中提到的问题。 选项B最初是为了测试该概念而编写的,尽管它是硬编码的,但它仍然有效。选项A是对选项B进行概括的一种尝试,但是,尽管变量变量在最前面,但变量word似乎并没有得到更新,并且它一直在读取原始单词数组。
答案 0 :(得分:0)
有两个问题共同导致该问题。修复任何一个问题都可以防止更大的问题。
第一个问题是filter
是一个惰性迭代器。它实际上并不会立即处理其输入。当您在其输出迭代器上进行迭代时,它只会跳过错误的值。如果您可以尽早退出迭代,那是一件好事,但是在这里有问题。您可以通过使用非惰性方法进行过滤来避免问题,例如列表理解(或者您可以进行list(filter(...))
):
for i in range(1,len(word)):
words = [x for x in words if x[i] == word[i]]
懒惰的filter
有问题的原因是我们的第二个问题。这是因为您的lambda
函数是闭包。他们正在从封闭的名称空间而不是从自己的名称空间读取i
变量。不幸的是,由于i
会随着循环的进行而不断在外部命名空间中变化,因此它们最终都会看到最后一个i
值,而不是定义时的值i
。有一个解决方法,就是使用i
作为lambda
中的参数,并将其当前值(在外部名称空间中)作为默认值:
for i in range(1,len(word)):
words = filter(lambda x, i=i: x[i] == word[i], words)
请注意,这些修复都不会导致非常有效的前缀匹配。对于真正有效的搜索,您可能只想加载一次数据文件,并构建一个可以有效搜索前缀的数据结构。默认情况下,trie会执行此操作,但是如果您不想自己构建(或使用库),则如果您没有太多单词,则从前缀到完整字符串的基本字典映射可能是合理的。