простое решение
простое решение заключается в использовании collections.defaultdict
:
from collections import defaultdict
def make_chains(input_list):
"""
Takes an input text as a list of strings and returns a dictionary of markov chains.
"""
chain = defaultdict(list)
for line in input_list:
line = line.replace(',', "")
words = line.split()
for i in range(0, len(words) - 2):
chain[words[i], words[i + 1]].append(words[i + 2])
return chain
с этим, то вы получите:
$ print make_chains(["Would you like", "Would you could"])
defaultdict(<type 'list'>, {('Would', 'you'): ['like', 'could']})
Закрепление оригинального
Точно так же вы можете получить лучшее представление о том, что пошло не так в вашем коде, однако, мы можем зафиксировать оригинальное решение без использования defaultdict. Для этого есть несколько вещей, которые нужно упомянуть о вашем исходном коде.
Для начала, давайте посмотрим на это заявление:
words_copy = words
Не делать то, что вы думаете, что делает, да и не нужно. Это не создает копию words
, она просто создает новую переменную words_copy
и указывает ее на существующее значение words
. Поэтому, если вы меняете words
, вы меняете words_copy
.
Что бы вы хотели, это words_copy = copy.deepcopy(words)
, но это не нужно в этом случае, так как вы не меняете состояние words
, когда выполняете итерацию.
Далее эта линия:
if dict[(words[word], words[word + 1])] in dict:
dict.update(words[word+2])
имеет несколько недостатков. Во-первых, если кортеж еще не указан в dict, то это вызовет ошибку ключа. Это наверняка произойдет на первой итерации. Во-вторых, метод обновления dict добавляет переданный dict к dict, который вы вызываете. То, что вы хотите сделать, это обновить значение dict на этом ключе.
Так что вы хотите:
if (words[word], words[word + 1]) in dict:
# Add to the existing list
dict(words[word], words[word + 1]).append(words[word+2])
else:
# Create a new list
dict(words[word], words[word + 1]) = [words[word+2]]
Наконец, этот блок не является необходимым:
if word == len(words_copy) - 3:
break
Вместо этого, просто итерацию до третьего по последнему индексу, как в:
for word in range(0, len(words) - 2):
Введя это полностью, вы можете использовать эти изменения, чтобы исправить исходную версию:
def make_chains(corpus):
"""Takes an input text as a string and returns a dictionary of
markov chains."""
dict = {}
for line in corpus:
line = line.replace(',', "")
words = line.split()
for word in range(0, len(words) - 2):
if (words[word], words[word + 1]) in dict:
# Add to the existing list
dict[(words[word], words[word + 1])].append(words[word + 2])
else:
# Create a new list
dict[(words[word], words[word + 1])] = [words[word + 2]]
return dict
Надеюсь, это поможет!
посмотрите на 'collections.defaultdict'. – HuStmpHrrr
Вы ищете 'defaultdict' в' collections'. Просто скажите 'd = collections.defaultdict (list)', и теперь каждый элемент представляет собой пустой список. Кстати, не назовите свою переменную 'dict', так как она столкнется с типом того же имени. – rlbond