2016-02-05 27 views
5

Sto cercando di scrivere un codice, che prende una frase:Python - condanna a un dizionario

dimension implies direction implies measurement implies the more and the less 

e lo converte in un dizionario, dove le parole = chiave e il valore = parole precedenti, ma per la prima parola non ha valore.

Dovrebbe essere essenzialmente:

{'and' : 'more' 

'dimension' : '' 

'direction' : 'implies' 

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

'less' : 'the' 

'measurement' :'implies' 

'more' : 'the' 

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

ho scritto:

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] 

ma non aggiungere il valore al valore esistente di una chiave, ma piuttosto lo sostituisce, così, invece di ottenendo 3 valori diversi per 'implies' Ricevo solo 1 valore.

Inoltre, anziché assegnare un valore NO alla dimensione della parola, lo assegna meno (dal -1).

+0

Mi chiedevo se l'aggiunta di: 'se i == 0: stenence_dict [words_list [i]] = ''' aiuterebbe ad ottenere il valore vuoto per primo indice – Nume

+0

Perché si assegnando 'sentence_dict [words_list [i ]] = words_list [i-1] 'non aggiungendo il valore esistente. Si dovrebbe verificare per 'i == 0' per la prima parola. – ismailsunni

+1

come nota a margine: il primo loop coulp deve essere sostituito con un loop diretto sulle parole –

risposta

6

Ecco come farlo senza un 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) 

uscita

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

quindi l'idea è di creare una nuova lista chiamata prev? – Nume

+0

scusate un po 'confuso su cosa stia realmente accadendo nel codice – Nume

+0

@Nume: 'prev' è solo una stringa. Contiene la ** parola precedente. All'inizio del ciclo contiene una stringa vuota. –

2

Basta dividere la stringa in un elenco e creare un altro elenco sfalsando con una stringa vuota prefisso, quindi comprimerlo e creare il dizionario iterandolo, PS: utilizzare defaultdict inizializzato con l'elenco anziché il dizionario a causa della possibilità di più valori per una singola chiave.

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 

Se non si desidera importare qualsiasi cosa inizializzare il dict consistere lista vuota quindi utilizzare la stessa logica

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

non è possibile importare nulla in più nella funzione/programma. – Nume

+0

Ho pensato di fare uno spazio vuoto e aggiungerlo alla stringa, ma poi (con il mio codice) ottengo "": "less" anche nel dizionario. – Nume

+0

@ PM2Ring Grazie, cambiato :) – k4vin

0

Se non si è autorizzati a importare nulla poi un ingegnoso reduce operazione insieme a slicing e zip (tutti questi sono Python built-in, che non richiede l'importazione) potrebbe essere un modo molto compatto per farlo:

EDIT Dopo avermi fatto notare che avevo frainteso il problema, l'ho risolto modificando l'istruzione 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]), {}) 

E in uscita il risultato (anche a cura)

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

Per completezza, il vecchio, erronei, risultato:

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

Un po 'di spiegazione

Dopo aver diviso la stringa in un elenco di parole, possiamo indicizzare le singole parole come words[i].

modificato In base all'affermazione del problema, i tasti del dict risultante sono le parole che seguono una parola, il valore è la prima parola. Quindi dobbiamo trasformare la lista di parole in una lista di combinazioni di ogni parola con la parola successiva. Quindi la lista di key sarà la lista [parole [1], parole [2], parole [3], ....] e lo values che vanno con quelli sono: [parole [0], parole [1 ], parole [2], ..., parole [n-1]].

Usare Python slicing: keys = words[1:] e values = words[:-1]

Ora abbiamo bisogno di creare un dict di quelle chiavi e valori, aggregando i valori in un list, se la stessa chiave si verifica più volte.

Un dict ha un metodo .setdefault(key, value) che inizializza valore s' key a value se key non è in ancora il dict, altrimenti restituisce il valore come è attualmente. Per impostazione predefinita, inizializzando tutti i valori sul numero vuoto list ([]), possiamo chiamare ciecamente .append(...) su di esso. Questo è ciò che questa parte del codice fa:

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

Poi c'è reduce. Un'operazione di riduzione riduce (...) un elenco di valori in uno. In questo caso ridurremo un elenco di tuple (key, value) in un dict in cui abbiamo accumulato tutti i valori nella rispettiva chiave.

reduce accetta una funzione di riduzione della richiamata e un elemento iniziale. L'elemento iniziale qui è il dict vuoto {} - lo riempiremo mentre procediamo.

La funzione di riduzione della richiamata viene richiamata ripetutamente con due argomenti, l'accumulatore e l'elemento successivo da aggiungere all'accumulo. La funzione dovrebbe restituire il nuovo accumulatore.

In questo codice, il passaggio di riduzione è sostanzialmente l'aggiunta del valore dell'elemento all'elenco di valori per la chiave dell'elemento. (Vedi sopra - questo è ciò che fa lo .setdefault().append()).

Tutto ciò che serve è ottenere un elenco di tuple (key, value) che è necessario elaborare. È qui che viene visualizzato il numero zip incorporato. zip accetta due elenchi e restituisce un elenco di tuple di elementi corrispondenti.

Così:

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

produce esattamente quello che vogliamo: la lista di tutti (key, value) tuple.

Infine, poiché la funzione di riduzione deve restituire il nuovo accumulatore, dobbiamo giocare un trucco. list.append(...) restituisce None, anche se il ditt effettivo è stato modificato. Quindi non possiamo restituire quel valore come accumulatore successivo. Quindi aggiungiamo la costruzione or acc dopo.

Poiché il lato sinistro della logica or restituisce sempre None, che è logicamente False in Python, il lato destro è sempre 'valutata' - in questo caso la (modificato) dict stesso. Il risultato netto dello or valuta quindi il dict modificato stesso, che è esattamente quello che dobbiamo restituire.

+0

Sembra che tu abbia frainteso l'affermazione del problema. _ Ogni parola nella frase è una chiave. –

+0

Davvero, grazie per averlo notato. Accidenti. – haavee

+0

Fortunatamente è un cambiamento facile in questo codice! – haavee