2016-02-05 4 views
5

Я пытаюсь написать код, который принимает предложение:Python - предложение к словарю

dimension implies direction implies measurement implies the more and the less 

и преобразует его в словарь, где слова = ключ и значение = предыдущие слова, но и для в первом слове нет значения NO.

Оно должно быть по существу:

{'and' : 'more' 

'dimension' : '' 

'direction' : 'implies' 

'implies' : 'dimension', 'direction', 'measurement' 

'less' : 'the' 

'measurement' :'implies' 

'more' : 'the' 

'the' : 'and', 'implies'} 

Я писал:

def get_previous_words_dict(text): 
    words_list = text.split() 
    sentence_dict = {} 
    for i in range(0,len(words_list)): 
     sentence_dict[words_list[i]] = words_list[i-1] 

НО это не добавляет значение к существующему значению ключа, а заменяет его, так что вместо получение 3 разных значений для 'implies' Я получаю только 1 значение.

Кроме того, вместо присвоения значения NO размеру слова он присваивает его меньше (начиная с -1).

+0

мне было интересно, если добавление: 'если я == 0: stenence_dict [words_list [я]] = ''' бы помочь получить пустое значение для первого индекса – Nume

+0

Поскольку вы назначая 'sentence_dict [words_list [I ]] = words_list [i-1] 'не добавляя существующее значение. Вы должны проверить для 'i == 0' для первого слова. – ismailsunni

+1

в качестве примечания: первая петля цикла должна быть заменена прямым контуром над словами –

ответ

6

Вот как сделать это без defaultdict:

text = 'dimension implies direction implies measurement implies the more and the less' 
sentence_dict = {} 
prev = '' 
for word in text.split(): 
    if word not in sentence_dict: 
     sentence_dict[word] = [] 
    sentence_dict[word].append(prev) 
    prev = word 

print(sentence_dict) 

выход

{'and': ['more'], 'direction': ['implies'], 'implies': ['dimension', 'direction', 'measurement'], 'less': ['the'], 'measurement': ['implies'], 'the': ['implies', 'and'], 'dimension': [''], 'more': ['the']} 
+0

, поэтому идея состоит в том, чтобы просто создать новый список под названием prev? – Nume

+0

Извините, немного запутался относительно того, что на самом деле происходит в коде – Nume

+0

@Nume: 'prev' - это просто строка. Он содержит ** предыдущее слово. В начале цикла он содержит пустую строку. –

2

Просто разделите строку на список и создайте другой список, смещая с префиксом пустую строку, затем застегивайте ее и создавайте словарь, итерируя ее, PS - используйте defaultdict, инициализированный списком вместо словаря, из-за возможности несколько значений для одного ключа.

inp = "dimension implies direction implies measurement implies the more and the less" 
l1 = inp.split() 
l2 = [""]+l1; 
zipped = zip(l1,l2) 
from collections import defaultdict 
d = defaultdict(list) 
for k, v in zipped: 
    d[k].append(v) 
print d 

Если вы не хотите, чтобы импортировать любую вещь инициализировать Dict состоять из пустого списка затем использовать ту же логику

inp = "dimension implies direction implies measurement implies the more and the less" 
l1 = inp.split() 
l2 = [""]+l1; 
zipped = zip(l1, l2) 
d = {x: [] for x in l1} 
for k, v in zipped: 
    d[k].append(v) 
print d 
+0

, нам не разрешено импортировать ничего лишнего в функцию/программу. – Nume

+0

Я думал о том, чтобы делать пустое пространство и добавлять его в строку, но затем (с моим кодом) я получаю «»: «меньше» в словаре. – Nume

+0

@ PM2Ring Спасибо, изменил его :) – k4vin

0

Если вы не разрешено импортировать что-либо, то ловкий reduce операцию вместе с slicing и zip (все из них являются Python встроенные модули, не требующие импорта) может быть очень компактный способ сделать это:

EDIT После того, как он указал мне, что я неправильно понял проблему, исправил ее, изменив инструкцию zip().

# the string - split it immediately into a list of words 
# (some words deleted to make it smaller) 
words = "dimension implies direction implies the more and the less".split() 

# There is a **lot** going on in this line of code, explanation below. 
result = reduce(lambda acc, kv: acc.setdefault(kv[0], []).append(kv[1]) or acc, 
       zip(words[1:], words[:-1]), {}) 
# this was the previous - incorrect - zip() 
#    zip(words[1::2], words[0::2]), {}) 

и вывод результата (также отредактирован)

print result 
{'and': ['more'], 'direction': ['implies'], 'implies': ['dimension', 
'direction', 'measurement'], 'less': ['the'], 'measurement':['implies'], 
'the': ['implies', 'and'], 'more': ['the']} 

Для полноты, старый, ошибочный, результат:

print result 
{'the': ['and'], 'implies': ['dimension', 'direction', 'measurement'], 'more': ['the']} 

Немного объяснения

После разделения строки на список слов мы можем индексировать отдельные слова как words[i].

отредактировал К описанию проблемы ключи ключа, полученные в результате, - это слова, следующие за словом, значение которого является первым словом. Поэтому мы должны преобразовать список слов в список комбинаций каждого слова со следующим словом. Таким образом, список key будет представлять собой список [слова [1], слова [2], слова [3], ....] и values, которые идут с такими словами: [слова [0], слова [1 ], слова [2], ..., слова [n-1]].

Использование Python slicing: keys = words[1:] и values = words[:-1]

Теперь нам нужно создать dict этих ключей и значений, агрегирование значений в list, если же ключ происходит несколько раз.

dict имеет метод .setdefault(key, value) который будет инициализировать значение key «с до value, если key не в dict еще, в противном случае возвращает значение, как это в настоящее время. По умолчанию-инициализируя все значения пустым list ([]), мы можем вслепую называть .append(...). Это то, что делает эту часть кода:

acc.setdefault(key, []).append(value) 

Тогда есть reduce. Операция уменьшения уменьшает (...) список значений в один. В этом случае мы уменьшим список (key, value) кортежей в dict, где мы скопировали все значения в их соответствующий ключ.

reduce принимает функцию сокращения обратного вызова и начальный элемент. Исходным элементом здесь является пустой dict {} - мы будем заполнять это, когда мы идем.

Функция уменьшения обратного вызова вызывается многократно с двумя аргументами, аккумулятором и следующим элементом для добавления к накоплению. Функция должна вернуть новый аккумулятор.

В этом коде шаг восстановления в основном является добавлением значения элемента в список значений для ключа элемента. (См. Выше - вот что делает .setdefault().append()).

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

Таким образом:

zip(words[1:], words[:-1]) 

производит именно то, что мы хотим: список всех (key, value) кортежей.

Наконец, поскольку функция уменьшения должна возвращать новый аккумулятор, мы должны сыграть трюк. list.append(...) возвращает None, хотя фактический dict был изменен. Таким образом, мы не можем вернуть это значение в качестве следующего аккумулятора. Таким образом, после этого мы добавляем конструкцию or acc.

Поскольку левая сторона логической or всегда имеет значение None, которое логически False в Python, правая рука всегда «оценивается» - в этом случае (модифицированный) Сыроватского себя. Таким образом, итоговый результат or оценивает сам модифицированный dict, что и нужно вернуть.

+0

Вы, кажется, неправильно поняли постановку проблемы. _Все слово в предложении является ключом. –

+0

Действительно у меня есть, спасибо за то, что заметили. Вот это да. – haavee

+0

К счастью, это очень простое изменение в этом коде! – haavee

Смежные вопросы