简体   繁体   中英

Unhashable type: 'list' error in python

I have this dictionary:

final = {0: [1, 9], 1: [0, 9], 8: [16, 10], 9: [0, 1], 10: [8, 16], 16: [8, 10]}

And I wanted to convert it to a list, so I used list comprehensions and the result was the following:

myList = [[int(k)]+v for k, v in final.items()]
myList = [[0, 1, 9], [0, 1, 9], [0, 1, 9], [8, 10, 16], [8, 10, 16], [8, 10, 16]]

I also wanted the whole list as well as the elements inside of every small list to be sorted and to erase the duplicates from the list:

for i in myList:
   i.sort()

myList.sort()
list(set(myList))
print(myList)

However, when I run this i get the error " Unhashable type: 'list' " . Is there any other way to implement this? Thank you in advance!

A list is mutable; in Python mutable containers are not hashable. set in turn equires the items to be hashable. You can convert the lists to tuples, which are immutable containers and thus hashable:

>>> myList = [[0, 1, 9], [0, 1, 9], [0, 1, 9], [8, 10, 16], [8, 10, 16], [8, 10, 16]]
>>> list(set(tuple(i) for i in myList))
[(8, 10, 16), (0, 1, 9)]

Note that sets are not sorted so you'd probably want to sort after making the set:

>>> myList = [[0, 1, 9], [0, 1, 9], [0, 1, 9], [8, 10, 16], [8, 10, 16], [8, 10, 16]]
>>> sorted(set(tuple(i) for i in myList))
[(0, 1, 9), (8, 10, 16)]

If you are only sorting the sublists to remove dupes you can use frozensets instead and avoid sorting:

final = {0: [1, 9], 1: [0, 9], 8: [16, 10], 9: [0, 1], 10: [8, 16], 16: [8, 10]}

unique = list(map(list, {frozenset([k] + v) for k, v in final.items()}))

Which will give you:

[[0, 1, 9], [16, 8, 10]]

You could still sort the remaining sublists which would still be faster than sorting them all first and then removing especially if the sublists are large and/or you have a lot of dupes.

unique = list(map(sorted, {frozenset([k] + v) for k, v in final.items()}))

print(unique)

Which will give you ordered output if necessary:

[[0, 1, 9], [8, 10, 16]]

A set needs a list of hashable objects; that is, they are immutable and their state doesn't change after they are created. A list object is mutable however, because it can change (as shown by the sort function, which permanently rearranges the list) which means that it isn't hashable so doesn't work with set .

The solution to this is to convert the list objects to tuple objects; these will work with set because they're hashable. You could do this by creating a generator which you then pass to set:

>>> list(set(tuple(x) for x in myList))
[(0, 1, 9), (8, 10, 16)]

Tuples work in a similar way to lists, so this shouldn't cause any problems with your existing program. If you did need a list of lists though, you could convert it back by using a list comprehension like this:

>>> [list(x) for x in set(tuple(x) for x in myList))]
[[0, 1, 9], [8, 10, 16]]

Sure. Change:

myList = [[int(k)]+v for k, v in final.items()]

To:

myList = [tuple([int(k)]+v) for k, v in final.items()]

This creates a tuple rather than a list for your combination of dictionary keys and values. Tuples are immutable and can be used as values in sets, whereas lists can't.

myList is a list of lists. When you build a set the elements of the set must be immutable for sets to work properly.

In this case lists are mutable (You can append or remove items), this is necessary for sets cause if you could change the content of the lists python wouldn't be able to tell if your set has repeated elements or not.

Imagine this case (IT'S NOT POSSIBLE, but imagine it):

l1 = [1,2,3]
l2 = [1,2]
s = set([l1, l2]) #Here both lists are different
l2.append(3) #Here both lists are equal

Python should infer that you want l1 or l2 to be eliminated from the set? Which one? Why?

One thing you can do is use tuples instead of lists (Which are an immutable version of lists) and the convert it to sets

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM