Python — эффективная работа с большими перестановочными списками

Я написал короткий скрипт Anagram Solver на Python 2.7.

#Import Permutations Module
from itertools import permutations as perm

#Defined Functions
def check(x,y):

    #Opens Dictionary File
    with open('wordsEn.txt') as dictionary:

        '''Checks the permutations against all of the dictionary words and appends
        any matching ones to on of the empty lists'''

        for line in dictionary:
            for i in x:
                if i + '\n' == line:
                    y.append(i)

#Empty Lists that will be appended to later
anagram_perms = []
possible_words = []

#Anagram User Input
anagram = list(raw_input("Input scrambled word: ").lower())

#Creates single list items from the permutations, deletes duplicates
for char in perm(anagram):
    anagram_perms.append("".join(char))
    anagram_perms = list(set(anagram_perms))

#Uses the defined function
check(anagram_perms, possible_words)

#Prints the number of perms created, then prints the possible words beneath it
print len(anagram_perms)
print '\n'.join(possible_words)

По сути, он берет введенную пользователем анаграмму, генерирует и помещает в список все возможные комбинации букв (используя itertools.permutations), удаляя любые дубликаты. Затем он сравнивает каждую из этих комбинаций с текстовым файлом словаря из 100 000 слов, помещая любые совпадающие слова в список для печати.

Я столкнулся с проблемой, что если пользователь вводит слово, длина которого превышает 6 уникальных букв, количество сгенерированных перестановок вызывает зависание и сбой. Типичным вводом будут 9-буквенные анаграммы, однако очевидно, что они будут выводить перестановки 362880 ('9!'), если все буквы разные, что невозможно.

У меня есть несколько потенциальных решений:

  1. Создание ряда пустых списков, которые могут содержать только определенное количество добавленных перестановок. Как только эти списки заполнены, перестановки добавляются к следующему. Затем каждый из этих списков сверяется с текстовым файлом.
  2. Создание одного пустого списка, содержащегося в цикле. Перестановки генерируются и добавляются к списку до определенного рабочего числа, затем список используется для проверки текстового файла перед его очисткой и добавлением следующего количества перестановок.
  3. Какой-то другой метод, при котором создается определенное количество перестановок, затем процесс приостанавливается, пока текущие сгенерированные перестановки проверяются на соответствие текстовому файлу, а затем возобновляются и повторяются.

Однако я новичок в разработке Python и действительно не знаю, возможно ли это или как я буду внедрять их в свой код; и другие вопросы по подобным темам толком не смогли помочь.

Если кто-то хочет увидеть мой код до сих пор, я был бы рад сжать его и опубликовать, но ради того, чтобы больше не задавать этот вопрос, я оставлю его, если он не будет запрошен. (обновлено выше)

Спасибо!


person Hexbob6    schedule 28.08.2016    source источник
comment
пожалуйста, опубликуйте свой код.   -  person James    schedule 29.08.2016
comment
Пожалуйста, опубликуйте свой код, краткую информацию о том, что делает ваш код (BRIEF), пример ввода и требуемый вывод (или проблему, с которой вы столкнулись). В противном случае никто не будет читать так много, а если кто-то и прочитает, то вряд ли поймет. Пожалуйста, помогите нам помочь вам :)   -  person Anonymous    schedule 29.08.2016
comment
@MoinuddinQuadri, я не был уверен, что преимущества добавления кода, но увеличение длины вопроса стоили бы того и побуждали людей читать, но, конечно же, я соберу и добавлю его :)   -  person Hexbob6    schedule 29.08.2016
comment
Сообщество StackOverflow поможет вам решить вашу проблему, но нам также необходимо увидеть усилия, которые вы приложили для ее решения.   -  person Anonymous    schedule 29.08.2016
comment
@MoinuddinQuadri Хорошо, спасибо, обновлено выше :)   -  person Hexbob6    schedule 29.08.2016


Ответы (2)


Он считает, что лучшим решением может быть отказ от использования перестановок. Гораздо более вероятно, что большинство сгенерированных перестановок не являются словом, поэтому генерировать их все пустая трата времени.

Вы можете рассмотреть возможность предварительной обработки этого словаря в словарь отсортированных букв в список слов, из которых состоят эти буквы. Затем ваш решатель анаграмм будет простым поиском в словаре после сортировки ввода.

Сначала создайте словарь из списка слов и сохраните его в файл:

from collections import defaultdict
import json

word_list = ['tab', 'bat', 'cat', 'rat', ...]  # 100k words
word_dict = defaultdict(list)
for word in word_list:
    word_dict[''.join(sorted(word))].append(word)
with open('word_dict.json') as f:
    f.write(json.dumps(dict(word_dict)))

Затем при запуске кода анаграммы загрузите словарь и используйте его для поиска отсортированного ввода:

import json

empty_list = []
with open('word_dict.json', 'r') as f:
    word_dict = json.loads(f.read())

while True:
    anagram = raw_input('Enter in an anagram: ')
    sorted_anagram = ''.join(sorted(anagram))
    print word_dict.get(sorted_anagram, empty_list)
person Karin    schedule 28.08.2016
comment
Интересно, я как-то не рассматривал его таким образом, спасибо! Я не думаю, что это именно то, что вы говорите, но это заставило меня задуматься... Могу ли я просто написать код, который просматривает каждую строку текстового файла словаря и говорит: «Если эта строка содержит все введенные анаграммы? буквы один раз в любом порядке, затем добавить их в список возможных_слов, иначе перейти к следующей строке? - person Hexbob6; 29.08.2016
comment
Да, но это будет медленнее, чем подход со словарем, поскольку вам придется перебирать словарь и подсчитывать буквы в каждой итерации цикла. - person Karin; 29.08.2016
comment
Истинный. Итак, поправьте меня, если я ошибаюсь, вы говорите, что сначала получите длину введенной анаграммы и используйте ее, чтобы поместить все слова одинаковой длины из текстового файла в словарь, а затем проверьте, какие из них эти слова имеют те же буквы, что и анаграмма, и добавить их в список? :) Не могли бы вы добавить пару комментариев к вашему коду, так как есть одна или две вещи, которые я не совсем понимаю? - person Hexbob6; 29.08.2016
comment
Ах, извините, я думаю, что мои ограниченные знания python здесь не помогают, и я все еще не понимаю его должным образом. Список из 100 тысяч слов представляет собой файл .txt, вы говорите, что я должен сначала добавить их все в список (word_list), а затем продолжить оттуда? И в чем преимущество импорта модуля json? - person Hexbob6; 29.08.2016
comment
Предлагается взять ваш файл .txt и выполнить однократное преобразование этого файла в другой файл .json, содержащий словарь, который я описал. Затем вы должны использовать этот файл .json вместо файла .txt. Модуль json помогает сериализовать и десериализовать словарь. - person Karin; 29.08.2016

Это должно помочь. Функция itertools.permutations возвращает итератор. Это означает, что весь список не хранится в памяти; скорее вы можете вызвать следующее значение, и оно вычислит то, что необходимо на лету.

from itertools import permutations

with open('./wordlist.txt', 'r') as fp:
    wordlist_str = fp.read()
    wordlist = set(wordlist_str.lower().split('\n'))  #use '\r\n' in Windows

def get_anagrams(word):
    out = set()
    for w in permutations(word.lower()):
        if ''.join(w) in wordlist:
            out.add(''.join(w))
    return out
person James    schedule 28.08.2016