2012-12-02 10 views
32

Sto cercando di prendere un file che assomiglia a questoPython: TypeError: Tipo di calcolo dell'hash: 'list'

AAA x 111 
AAB x 111 
AAA x 112 
AAC x 123 
... 

E utilizzare un dizionario per modo che l'output simile a questo

{AAA: ['111', '112'], AAB: ['111'], AAC: [123], ...} 

Questo è quello che ho provato

file = open("filename.txt", "r") 
readline = file.readline().rstrip() 
while readline!= "": 
    list = [] 
    list = readline.split(" ") 
    j = list.index("x") 
    k = list[0:j] 
    v = list[j + 1:] 
    d = {} 
    if k not in d == False: 
     d[k] = [] 
    d[k].append(v) 
    readline = file.readline().rstrip() 

continuo a ricevere un TypeError: tipo di calcolo dell'hash: 'list'. So che le chiavi di un dizionario non possono essere elenchi, ma sto cercando di rendere il mio valore in un elenco non come chiave. Mi chiedo se ho fatto un errore da qualche parte.

Grazie a tutti quelli che mi hanno aiutato con la mia ultima domanda.

risposta

20

Come indicato dalle altre risposte, l'errore è dovuto a k = list[0:j], in cui la chiave viene convertita in un elenco. Una cosa che si potrebbe provare rielabora il codice per sfruttare la funzione di split:

# Using with ensures that the file is properly closed when you're done 
with open('filename.txt', 'rb') as f: 
    d = {} 
    # Here we use readlines() to split the file into a list where each element is a line 
    for line in f.readlines(): 
    # Now we split the file on `x`, since the part before the x will be 
    # the key and the part after the value 
    line = line.split('x') 
    # Take the line parts and strip out the spaces, assigning them to the variables 
    # Once you get a bit more comfortable, this works as well: 
    # key, value = [x.strip() for x in line] 
    key = line[0].strip() 
    value = line[1].strip() 
    # Now we check if the dictionary contains the key; if so, append the new value, 
    # and if not, make a new list that contains the current value 
    # (For future reference, this is a great place for a defaultdict :) 
    if key in d: 
     d[key].append(value) 
    else: 
     d[key] = [value] 

print d 
# {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']} 

Si noti che se si sta utilizzando Python 3.x, si dovrà fare un aggiustamento minore per farlo funzionare correttamente. Se apri il file con rb, devi utilizzare line = line.split(b'x') (il che ti assicura di dividere il byte con il tipo corretto di stringa).È inoltre possibile aprire il file utilizzando with open('filename.txt', 'rU') as f: (o anche with open('filename.txt', 'r') as f:) e dovrebbe funzionare correttamente.

+0

Ho provato questo e ottengo TypeError: tipo str non supporta l'API buffer sulla riga "line = line.split ('x')" – Keenan

+0

@ user1871081 Ah, stai usando Python 3.x? Pubblicherò un aggiornamento che dovrebbe funzionare con quello. – RocketDonkey

+1

@ user1871081 Fantastico, buona fortuna con tutto. – RocketDonkey

10

Si sta tentando di utilizzare k (che è un elenco) come chiave per d. Le liste sono mutabili e non possono essere utilizzate come chiavi dict.

Inoltre, non si è mai l'inizializzazione delle liste nel dizionario, a causa di questa linea:

if k not in d == False: 

che dovrebbe essere:

if k not in d == True: 

che dovrebbe in realtà essere:

if k not in d: 
+0

Anche con il cambiamento dà ancora lo stesso errore. – Keenan

0

TypeError sta accadendo perché k è un elenco, poiché è stato creato una fetta da un'altra lista con la riga k = list[0:j]. Questo dovrebbe probabilmente essere qualcosa come k = ' '.join(list[0:j]), quindi hai una stringa.

In aggiunta a ciò, l'istruzione if non è corretta come indicato dalla risposta di Jesse, che dovrebbe essere if k not in d o if not k in d (preferisco quest'ultima opzione).

Si sta inoltre cancellando il dizionario su ogni iterazione poiché si dispone di d = {} all'interno del ciclo for.

Si noti che non si dovrebbe inoltre utilizzare list o file come nomi di variabili, dal momento che si maschereranno i builder.

Ecco come vorrei riscrivere il codice:

d = {} 
with open("filename.txt", "r") as input_file: 
    for line in input_file: 
     fields = line.split() 
     j = fields.index("x") 
     k = " ".join(fields[:j]) 
     d.setdefault(k, []).append(" ".join(fields[j+1:])) 

Il metodo dict.setdefault() sopra sostituisce la logica if k not in d dal codice.

+0

mentre la preferenza è piena, 'non k in d' potrebbe confondere un novizio come' (non k) in d', mentre 'k non in d' non ha ambiguità –

+0

Direi anche che è il 'pythonic' il modo in cui 'not in' è elencato come [operatore] (http://docs.python.org/2/reference/expressions.html#not-in). –

+0

Sì, penso che la mia preferenza derivi probabilmente dall'apprendimento di altre lingue prima, dove per qualcosa come un test di contenimento non avresti operatori per questo, quindi dovresti fare qualcosa come '! A.contains (b)'. 'not in' potrebbe essere più pythonic, trovo il concetto di due operatori di parole più confuso che usare un inverso su un'espressione booleana. –

2

Il motivo per cui si sta verificando l'eccezione unhashable type: 'list' è perché k = list[0:j] imposta k come una "sezione" dell'elenco, che è un'altra lista, solitamente più breve. Quello di cui hai bisogno è ottenere solo il primo elemento in elenco, scritto in questo modo k = list[0]. Lo stesso per v = list[j + 1:] che dovrebbe essere solo v = list[2] per il terzo elemento della lista restituita dalla chiamata a readline.split(" ").

Ho notato molti altri probabili problemi con il codice, di cui ne menzionerò alcuni. Uno grande è che non si desidera inizializzare d ogni volta all'interno del ciclo con il d = {} come ogni riga viene letto. Un altro è che non è una buona idea denominare le variabili allo stesso modo del tipo built-in perché ti impedirà di accedere a quella built-in quando ne hai bisogno — e confonde gli altri che sono abituati a quei nomi che sono per le cose standard. Pertanto, per questo motivo, è necessario rinominare la variabile list in modo da evitare qualsivoglia problema.

Ecco una versione funzionante del tuo con queste modifiche in esso, ho anche semplificato l'espressione di dichiarazione if che hai che controlla per vedere se la chiave è già nel dizionario — ci sono modi ancora più semplici impliciti per farlo, ma questo il modo è abbastanza buono per ora.

d = {} 
file = open("filename.txt", "r") 
readline = file.readline().rstrip() 
while readline: 
    lst = readline.split(" ") # split into list like ['AAA', 'x', '111'] 
    k = lst[0] # first item 
    v = lst[2] # third item 
    if k not in d: # new key? 
     d[k] = [] # initialize value 
    d[k].append(v) 
    readline = file.readline().rstrip() 

print 'd:', d 

uscita:

d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']} 
-1
python 3.2 

    with open("d://test.txt") as f: 
       k=(((i.split("\n"))[0].rstrip()).split() for i in f.readlines()) 
       d={} 
       for i,_,v in k: 
         d.setdefault(i,[]).append(v) 
Problemi correlati