web-dev-qa-db-fra.com

Python: TypeError: type inshashable: 'list'

J'essaie de prendre un fichier qui ressemble à ceci

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

Et utilisez un dictionnaire pour que la sortie ressemble à ceci

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

C'est ce que j'ai essayé

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

Je continue à recevoir un TypeError: unhashable type: 'list'. Je sais que les clés d'un dictionnaire ne peuvent pas être des listes, mais j'essaie de faire de ma valeur une liste et non la clé. Je me demande si j'ai commis une erreur quelque part.

55
Keenan

Comme indiqué par les autres réponses, l'erreur est due à k = list[0:j], où votre clé est convertie en liste. Une chose que vous pouvez essayer est de retravailler votre code pour tirer parti de la fonction 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']}

Notez que si vous utilisez Python 3.x, vous devrez faire un ajustement mineur pour que cela fonctionne correctement. Si vous ouvrez le fichier avec rb, vous devrez utiliser line = line.split(b'x') (pour vous assurer de fractionner l'octet avec le type de chaîne approprié). Vous pouvez également ouvrir le fichier en utilisant with open('filename.txt', 'rU') as f: (ou même with open('filename.txt', 'r') as f:) et cela devrait fonctionner correctement.

34
RocketDonkey

Vous essayez d'utiliser k (qui est une liste) comme clé pour d. Les listes sont modifiables et ne peuvent pas être utilisées comme clés de dictée.

En outre, vous n'initialisez jamais les listes du dictionnaire, à cause de cette ligne:

if k not in d == False:

Ce qui devrait être:

if k not in d == True:

Ce qui devrait être réellement:

if k not in d:
11
Jesse the Game

Remarque: Cette réponse ne répond pas explicitement à la question posée. les autres réponses le font. Puisque la question est spécifique à un scénario} et que l'exception surélevée est générale, cette réponse pointe vers le cas général.

Les valeurs de hachage ne sont que des entiers utilisés pour comparer rapidement les clés de dictionnaire lors d'une recherche dans un dictionnaire.

En interne, la méthode hash() appelle la méthode __hash__() d'un objet qui est définie par défaut pour tout objet.

Conversion de une liste imbriquée en ensemble _

>>> a = [1,2,3,4,[5,6,7],8,9]
>>> set(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Cela se produit à cause de la liste dans une liste qui est une liste qui ne peut pas être hachée. Ce qui peut être résolu par convertir les listes imbriquées internes en un tuple},

>>> set([1, 2, 3, 4, (5, 6, 7), 8, 9])
set([1, 2, 3, 4, 8, 9, (5, 6, 7)])

Hachage explicite une liste imbriquée

>>> hash([1, 2, 3, [4, 5,], 6, 7])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


>>> hash(Tuple([1, 2, 3, [4, 5,], 6, 7]))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

>>> hash(Tuple([1, 2, 3, Tuple([4, 5,]), 6, 7]))
-7943504827826258506

La solution pour éviter cette erreur est de restructurer la liste pour avoir des nuplets imbriqués au lieu de listes.

7
All Іѕ Vаиітy

La raison pour laquelle vous obtenez l'exception unhashable type: 'list' est parce que k = list[0:j] définit k comme une "tranche" de la liste, qui est logiquement une autre liste, souvent plus courte. Ce dont vous avez besoin, c’est d’obtenir le premier élément de la liste, écrit comme suit: k = list[0]. Idem pour v = list[j + 1:] qui devrait simplement être v = list[2] pour le troisième élément de la liste renvoyée par l'appel à readline.split(" ").

J'ai remarqué plusieurs autres problèmes possibles avec le code, dont je mentionnerai quelques-uns. En gros, vous ne voulez pas (re) initialiser d avec d = {} pour chaque ligne lue dans la boucle. Une autre solution est que ce n’est généralement pas une bonne idée de nommer les variables de la même manière que les types intégrés, car cela vous empêchera d’avoir accès à l’une d’elles si vous en avez besoin - et cela déroute les autres qui sont habitués à la noms désignant l’un de ces éléments standard. Pour cette raison, vous devez renommer votre variable list variable pour ne plus avoir ce problème.

Voici une version de travail de votre avec ces modifications, j’ai également simplifié l’expression if que vous aviez et qui vérifie si la clé est déjà dans le dictionnaire - il existe des façons implicites encore plus courtes de faire ce genre de chose, mais déclaration conditionnelle est bien pour le moment.

d = {}
file = open("filename.txt", "r")
readline = file.readline().rstrip()
while readline:
    lst = readline.split(" ") # Split into sequence like ['AAA', 'x', '111'].
    k = lst[0]  # First item.
    v = lst[2]  # Third item.
    if k not in d:  # New key?
        d[k] = []  # Initialize its associated value to an empty list.
    d[k].append(v)
    readline = file.readline().rstrip()

file.close()  # Done reading file.
print('d: {}'.format(d))

Sortie:

d: {'AAA': ['111', '112'], 'AAC': ['123'], 'AAB': ['111']}
4
martineau

La TypeError est en train de se produire car k est une liste, car elle est créée à l'aide d'une tranche d'une autre liste avec la ligne k = list[0:j]. Cela devrait probablement être quelque chose comme k = ' '.join(list[0:j]), donc vous avez une chaîne à la place.

De plus, votre déclaration if est incorrecte, comme l'indique la réponse de Jesse, qui devrait indiquer if k not in d ou if not k in d (je préfère ce dernier).

Vous effacez également votre dictionnaire à chaque itération puisque vous avez d = {} dans votre boucle for.

Notez que vous ne devez pas non plus utiliser list ou file en tant que noms de variable, car vous masquerez les modifications intégrées.

Voici comment je voudrais réécrire votre code:

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

La méthode dict.setdefault() ci-dessus remplace la logique if k not in d de votre code.

0
Andrew Clark