Python中的“Unhashable type: 'list'”错误

6

我有这个字典:

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

我希望把它转换成列表,因此我使用了列表推导式,结果如下:

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

我希望整个列表以及每个小列表中的元素都能被排序,并从列表中删除重复项:

for i in myList:
   i.sort()

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

然而,当我运行这段代码时,出现了错误 "Unhashable type: 'list' "。有没有其他实现方法?谢谢!

5个回答

3

列表是可变的;在Python中,可变容器不可哈希。而set则需要元素可哈希。您可以将列表转换为元组,它是不可变容器,因此可以哈希:

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

请注意,集合是无序的,因此您可能希望在创建集合后进行排序。
>>> 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)]

2
如果您只是对子列表进行排序以去重,可以使用frozensets来避免排序:
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()}))

这将给您:

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

如果子列表很大并且/或者你有很多重复项,那么仍然对剩余的子列表进行排序仍然比先对所有子列表进行排序,然后再删除更快。

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

print(unique)

如果需要,它将为您提供有序输出:
[[0, 1, 9], [8, 10, 16]]

1
一个set需要一组可哈希对象;也就是说,它们是不可变的,在创建后它们的状态不会改变。然而,list对象是可变的,因为它可以改变(如sort函数所示,它会永久地重新排列列表),这意味着它不可哈希,因此无法与set一起使用。
解决方法是将list对象转换为tuple对象;这些对象可以与set一起使用,因为它们是可哈希的。您可以通过创建一个生成器,然后将其传递给set来实现这一点:
>>> list(set(tuple(x) for x in myList))
[(0, 1, 9), (8, 10, 16)]

元组的工作方式与列表类似,因此这不应该对您现有的程序造成任何问题。但是,如果您确实需要一个列表嵌套的列表,您可以使用像这样的列表推导式将其转换回来:
>>> [list(x) for x in set(tuple(x) for x in myList))]
[[0, 1, 9], [8, 10, 16]]

1
当然。更改为:

确定。变更:

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

到:

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

这会创建一个元组而不是列表,用于您的字典键和值的组合。元组是不可变的,并且可以用作集合中的值,而列表则不能。

0

myList是一个列表的列表。当您构建一个集合时,集合的元素必须是不可变的,以使集合正常工作。

在这种情况下,列表是可变的(您可以appendremove项目),这对于集合是必要的,因为如果您可以更改列表的内容,Python 就无法确定您的集合是否具有重复元素。

想象一下这种情况(不可能,但请想象):

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应该推断出您想要从集合中删除l1或l2?哪一个?为什么?

您可以做的一件事是使用元组而不是列表(它们是列表的不可变版本),然后将其转换为集合


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接