Чтобы узнать, можете ли вы составить слово из набора букв [упс, я сделал это сам - я имел в виду «сбор»!], Вы хотите, чтобы каждая буква встречалась хотя бы нужное количество раз, поэтому яЯ думаю, что нам придется как-то работать там.По определению наборы 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: возвращение!Я удалил редактирование сообщества, которое не работает, потому что экземпляры Counter не могут быть хэшируемыми.]
Если скорость поиска важна, вы можете обменять память и время предварительного вычисления:
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']
[Хех.Я только что заметил, что самого «чертополоха» нет в списке, но это потому, что его нет в файле слов ..]
И да, очевидные «не слова» действительно присутствуют в файле слов:
>>> assert all(w in allwords for w in (wordsfrom('thistles', allwords_by_count)))
>>>