2012-12-02 12 views
32

Próbuję wziąć plik, który wygląda takPython: Błąd typu: rodzaj unhashable: „list”

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

i używać słownika tak, że wyjście wygląda tak

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

to co próbowałem

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() 

Wciąż otrzymuję TypeError: typ unhashable: 'list'. Wiem, że Klucze w słowniku nie mogą być listami, ale próbuję uczynić moją wartość na liście, a nie kluczem. Zastanawiam się, czy gdzieś popełniłem błąd.

Dziękuję wszystkim, którzy pomogli mi w moim ostatnim pytaniu.

Odpowiedz

20

Jak wskazują inne odpowiedzi, błąd jest spowodowany k = list[0:j], gdzie klucz jest konwertowany do listy. Jedną rzeczą, jaką można spróbować jest przerabianie kodu, aby skorzystać z funkcji 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']} 

Zauważ, że jeśli używasz Pythona 3.x, będziesz musiał dokonać drobnych korekt, aby działać poprawnie. Jeśli otworzysz plik pod numerem rb, będziesz musiał użyć line = line.split(b'x') (który upewnia się, że dzielisz bajt na właściwy typ łańcucha).Możesz również otworzyć plik, używając with open('filename.txt', 'rU') as f: (lub nawet with open('filename.txt', 'r') as f:) i powinien działać poprawnie.

+0

Próbowałem tego i otrzymuję TypeError: typ str nie obsługuje interfejsu API bufora na linii "line = line.split ('x')" – Keenan

+0

@ user1871081 Ah, używasz Pythona 3.x? Opublikuję aktualizację, która powinna z tym współpracować. – RocketDonkey

+1

@ user1871081 Awesome, powodzenia we wszystkim. – RocketDonkey

10

Próbujesz użyć k (która jest listą) jako klucza do d. Listy są zmienne i nie można ich używać jako kluczy dyktujących.

Ponadto, nigdy nie jesteś inicjalizacji list w słowniku, bo z tej linii:

if k not in d == False: 

które powinny być:

if k not in d == True: 

Jakie powinny być rzeczywiście:

if k not in d: 
+0

Nawet ze zmianą wciąż daje ten sam błąd. – Keenan

0

Numer TypeError dzieje się, ponieważ k jest listą, ponieważ jest tworzony usi ng wycinek z innej listy z linią k = list[0:j]. Prawdopodobnie powinno to być coś takiego jak k = ' '.join(list[0:j]), więc zamiast tego masz ciąg znaków.

Ponadto, twoje oświadczenie jest nieprawidłowe, jak odnotowano w odpowiedzi Jessego, które powinno brzmieć if k not in d lub if not k in d (Wolę to drugie).

Oczyszczasz też słownik w każdej iteracji, ponieważ masz d = {} wewnątrz pętli .

Należy pamiętać, że nie należy również używać list ani file jako nazw zmiennych, ponieważ będą maskowane wbudowane.

Oto jak bym przepisać kod:

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:])) 

Sposób dict.setdefault() powyżej zastępuje logikę if k not in d z kodu.

+0

podczas gdy preferowane jest twoje pełne prawo, 'not k in d' może zmylić nowicjusza jako' (nie k) w d', podczas gdy 'k nie w d' nie ma dwuznaczności –

+0

Powiedziałbym nawet, że jest to" pyton " sposób, w jaki '' nie w 'jest wymieniony jako [operator] (http://docs.python.org/2/reference/expressions.html#not-in). –

+0

Tak, myślę, że moje preferencje prawdopodobnie pochodzą od nauki innych języków, gdzie dla czegoś takiego jak test powstrzymywania nie miałbyś operatorów do tego, więc zrobiłbyś coś takiego jak "! A.contains (b)". "nie w" może być bardziej pythonic, po prostu uważam, że koncepcja operatorów dwóch słów jest bardziej zagmatwana niż użycie odwrotnego wyrażenia boolowskiego. –

2

Powodem, dla którego otrzymujesz wyjątek unhashable type: 'list' jest to, że k = list[0:j] ustawia k jako "kawałek" listy, co jest kolejną, zazwyczaj krótszą listą. Potrzebujesz tylko pierwszego elementu na liście, napisanego tak: k = list[0]. To samo dla v = list[j + 1:], które powinno być po prostu v = list[2] dla trzeciego elementu listy zwróconego z połączenia z readline.split(" ").

Zauważyłem kilka innych prawdopodobnych problemów z kodem, o których wspomnę tylko kilka. Duże jest to, że nie chcesz inicjować d za każdym razem w pętli z d = {}, ponieważ każda linia jest odczytywana. Innym jest to, że nie jest dobrym pomysłem nazywanie zmiennych takimi samymi, jak typy wbudowane, ponieważ uniemożliwia to dostęp do wbudowanego, gdy jest to potrzebne, i powoduje zamieszanie dla tych, którzy używają tych nazw, standardowe rzeczy. Z tego powodu należy zmienić nazwę zmiennej list na inną, aby uniknąć takiego problemu.

Oto działająca wersja z tymi zmianami w niej, Uproszczono również wyrażenie wypowiedzi if, które miałeś, aby sprawdzić, czy klucz jest już w słowniku — są jeszcze łatwiejsze, ukryte sposoby, aby to zrobić, ale to droga jest na razie wystarczająco dobra.

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 

wyjściowa:

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)