Я предполагаю, что это что-то вроде поиска возможных слов по набору плиток Эрудит, так что персонаж может повторяться столько раз, сколько повторяется в исходном списке.
Хитрость заключается в эффективной проверке каждого символа каждого слова в вашем файле слов на соответствие с набором из ваших исходных букв. Для каждого символа, если он найден в наборе тестов, удалите его из набора тестов и продолжайте; в противном случае слово не совпадает, и переходите к следующему слову.
Python имеет приятную функцию all
для тестирования набора условий, основанных на элементах последовательности. all
имеет дополнительную функцию, которая будет «замыкать», то есть, как только один элемент не выполнит условие, тесты больше не будут выполняться. Поэтому, если ваша первая буква в слове-кандидате - «z», а в исходных буквах нет «z», то нет смысла проверять больше букв в слове-кандидате.
Мой первый шанс написать это был просто:
matches = []
for word in wordlist:
testset = set(letters)
if all(c in testset for c in word):
matches.append(word)
К сожалению, здесь ошибка в том, что если исходные буквы содержат одну букву «m», слово с несколькими буквами «m» будет ошибочно совпадать, поскольку каждая буква «m» будет отдельно соответствовать данной букве «m» в исходном тестовом наборе. Поэтому мне нужно было убрать каждую букву в том виде, в каком она была найдена.
Я воспользовался тем фактом, что set.remove(item)
возвращает None, который Python рассматривает как логическое False
, и расширил выражение моего генератора, используемое при вызове all
. Для каждого слова в слове, если оно найдено в наборе тестов, я хочу дополнительно удалить его из набора тестов, например, (псевдокод, недопустимый Python):
all(c in testset and "remove c from testset" for c in word)
Поскольку set.remove возвращает None, я могу заменить приведенный выше бит на «not testset.remove (c)», и теперь у меня есть допустимое выражение Python:
all(c in testset and not testset.remove(c) for c in word)
Теперь нам просто нужно обернуть это в цикл, который проверяет каждое слово в списке (обязательно проверяйте новый набор тестов перед проверкой каждого слова, так как наш all
тест теперь стал разрушительным тестом):
for word in wordlist:
testset = set(letters)
if all(c in testset and not testset.remove(c) for c in word):
matches.append(word)
Последний шаг - сортировка совпадений по убыванию длины. Мы можем передать ключевую функцию для сортировки. Встроенный len
был бы хорош, но это будет сортировать по возрастанию длины. Чтобы изменить его на нисходящий, мы используем лямбду, чтобы дать нам не len
, а -1 * len
:
matches.sort(key=lambda wd: -len(wd))
Теперь вы можете просто распечатать самое длинное слово в совпадениях [0] или перебрать все совпадения и распечатать их.
(Я был удивлен, что этот метод грубой силы работает так хорошо. Я использовал список слов 2of12inf.txt, содержащий более 80 000 слов, и для списка из 10 символов я получаю список совпадений примерно через 0,8 секунды на мой маленький 1.99GHz ноутбук.)