Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python-给定输入字母的可能的英语单字字谜_Python_List_Set_Membership_Anagram - Fatal编程技术网

Python-给定输入字母的可能的英语单字字谜

Python-给定输入字母的可能的英语单字字谜,python,list,set,membership,anagram,Python,List,Set,Membership,Anagram,我知道以前有人问过这方面的变化,但我无法理解以前的任何实现,因为其中大多数都涉及使用集合和issubset方法 以下是我试图做的:我在字典里有一组单词和一个可能的字母列表。我想知道是否可以通过重新排列列表中的字母来组成集合的成员。以下是我当前的实现: def solve(dictionary, letters): for word in dictionary: #for each word in the dictionary if len(word) > len(

我知道以前有人问过这方面的变化,但我无法理解以前的任何实现,因为其中大多数都涉及使用集合和issubset方法

以下是我试图做的:我在字典里有一组单词和一个可能的字母列表。我想知道是否可以通过重新排列列表中的字母来组成集合的成员。以下是我当前的实现:

def solve(dictionary, letters):

    for word in dictionary: #for each word in the dictionary
        if len(word) > len(letters):   # first optimization, doesn't check words that are larger than letter set
            continue
        else: 
            scrambledword = "".join([b for b in sorted(list(word))]) #sorts the letters in each word
            if set(scrambledword).issubset(letters):
                print word


def main():
    dictionary = set([x.strip() for x in open("C:\\Python27\\dictionary.txt")])        
    letters = sorted(['v','r','o','o','m','a','b','c','d'])
    solve(dictionary, letters)


main()

这种实现的明显问题是,会发现一些单词在“字母”中使用了多个字母。例如,尽管字母列表中只有一个字母“a”和“r”,但单词“carboard”显示为有效单词。如何在列表上使用“issubset”方法?

要知道你是否能用一组字母拼成一个单词[oops,我自己做的——我的意思是“收集”!],你希望每个字母至少出现正确的次数,所以我想我们必须以某种方式计算其中的计数。根据定义,Python集不关心源列表中元素的数量。也许像

from collections import Counter

letters = ['v','r','o','o','m','a','b','c','d']
words = 'cardboard boom booom'.split()
letterscount = Counter(letters)

for word in words:
    wordcount = Counter(word)
    print word, all(letterscount[c] >= wordcount[c] for c in wordcount)
给予

cardboard False
boom True
booom False
计数器是一个方便的实用程序类:

>>> c = Counter(letters)
>>> c
Counter({'o': 2, 'a': 1, 'c': 1, 'b': 1, 'd': 1, 'm': 1, 'r': 1, 'v': 1})
>>> c['o']
2
>>> c['z']
0
[DSM:返回!我删除了一个社区编辑,它不起作用,因为计数器实例不可散列。]

如果需要考虑搜索速度,则可以权衡内存和预计算时间:

from collections import defaultdict, Counter
from itertools import combinations

# precomputations
allwords = open('/usr/share/dict/words').read().split() 
allwords = list(w for w in allwords if len(w) >= 3) # hack, /words contains lots of silliness
allwords_by_count = defaultdict(list)
for i, word in enumerate(allwords):
    allwords_by_count[frozenset(word)].append((word, Counter(word)))
    if i % 1000 == 0:
        print i, word


def wordsfrom(letters, words_by_count):
    lettercount = Counter(letters)
    for subsetsize in range(1, len(lettercount)+1):
        for subset in combinations(lettercount, subsetsize):
            for possword, posswordcount in words_by_count[frozenset(subset)]:
                if all(posswordcount[c] <= lettercount[c] for c in posswordcount):
                    yield possword

>>> wordsfrom('thistles', allwords_by_count)
<generator object wordsfrom at 0x1032956e0>
>>> list(wordsfrom('thistles', allwords_by_count))
['ess', 'sis', 'tit', 'tst', 'hei', 'hie', 'lei', 'lie', 'sie', 'sise', 'tie', 'tite', 'she', 'het', 'teth', 'the', 'els', 'less', 'elt', 'let', 'telt', 'set', 'sett', 'stet', 'test', 'his', 'hiss', 'shi', 'sish', 'hit', 'lis', 'liss', 'sil', 'lit', 'til', 'tilt', 'ist', 'its', 'sist', 'sit', 'shies', 'tithe', 'isle', 'sile', 'sisel', 'lite', 'teil', 'teli', 'tile', 'title', 'seit', 'sesti', 'site', 'stite', 'testis', 'hest', 'seth', 'lest', 'selt', 'lish', 'slish', 'hilt', 'lith', 'tilth', 'hist', 'sith', 'stith', 'this', 'list', 'silt', 'slit', 'stilt', 'liesh', 'shiel', 'lithe', 'shiest', 'sithe', 'theist', 'thesis', 'islet', 'istle', 'sistle', 'slite', 'stile', 'stilet', 'hitless', 'tehsil', 'thistle']

导入
集合
,我们定义了一个可散列的多集:

def Letters(x):
    return frozenset(Counter(x).items())
现在,我们将词汇表预处理为字母的dict->{anagram1,anagram2,…}:

vocabulary = ['apple', 'banana', 'rats', 'star', 'tars']
countsToWords = defaultdict(lambda: set())
for word in vocabulary:
    countsToWords[Letters(word)].add(word)
您的“求解”功能现在需要O(1)个时间:

例如:

print( solve('star') )
# {'tars', 'star', 'rats'} 

如果您寻找字谜,换句话说,您希望重新排列,但使用所有字谜(而不是仅使用子集),那么还有另一种解决方案

首先对词典中的所有单词进行预处理。给定一个单词,您将生成一个字母相同但按字母顺序书写的单词:

def alphabetize(word):
    "".join(sorted(word))
并将这些新词放入一套
newDictionary
然后,您的函数可以调用字母排序,并检查结果是否在字典中

def solve(newDictionary, letters):
    query = alphabetize(letters)
    return query in newDictionary

字母排序功能是字谜的一个特征:当且仅当两个单词在应用字母排序时产生相同的结果时,它们才是彼此的字谜。

如果len(word)>len(字母),“carboard”不会被
过滤掉吗:
?不会。因为单词的长度等于字母列表的长度。它工作正常,但在非常大的列表上速度非常慢。让我确保我了解了它的工作原理:因此循环将遍历单词中的所有字母,确保“字母列表”中字母的频率大于或等于实际单词中字母的频率?非常聪明的实现。我如何只打印最大字母的单词?我想使用“max()”函数,但我不知道它是如何工作的。我可能不得不收回关于它“速度太慢”的评论,因为我现在已经测试了我在其他线程上看到的以前的实现,它们的速度都是指数级的。荣誉但我仍在寻找对此的任何优化。@NinjaGecko:Error-第24行,在countsToWords.setdefault(key,{})中。add(word)TypeError:unhabable type:“Counter”这个实现非常快,但它不会给出长度小于字符串长度的单词。例如,solve('rabbit')将不会产生任何结果
def alphabetize(word):
    "".join(sorted(word))
def solve(newDictionary, letters):
    query = alphabetize(letters)
    return query in newDictionary