【问题标题】:TypeError: unhashable type: 'list' when using built-in set functionTypeError: unhashable type: 'list' when using built-in set function
【发布时间】:2012-11-07 23:39:43
【问题描述】:

我有一个包含多个列表作为其元素的列表

eg: [[1,2,3,4],[4,5,6,7]]

如果我使用内置的 set 函数从该列表中删除重复项,我会收到错误

TypeError: unhashable type: 'list'

我使用的代码是

TopP = sorted(set(TopP),reverse=True)

TopP 是一个列表,就像在例如以上

set() 的这种用法是错误的吗?还有其他方法可以对上述列表进行排序吗?

【问题讨论】:

  • 对于您提供的列表,您希望的输出是什么?

标签: python list duplicates


【解决方案1】:

绝对不是理想的解决方案,但是如果我将列表转换为元组然后对其进行排序,我会更容易理解。

mylist = [[1,2,3,4],[4,5,6,7]]
mylist2 = []
for thing in mylist:
    thing = tuple(thing)
    mylist2.append(thing)
set(mylist2)

【讨论】:

    【解决方案2】:

    集合要求它们的项目是可散列的。在 Python 预定义的类型中,只有不可变的类型(例如字符串、数字和元组)是可散列的。可变类型(例如列表和字典)不可散列,因为更改其内容会更改散列并破坏查找代码。

    由于您无论如何都要对列表进行排序,只需将重复删除放置在列表已排序的之后。这很容易实现,不会增加操作的算法复杂度,并且不需要将子列表更改为元组:

    def uniq(lst):
        last = object()
        for item in lst:
            if item == last:
                continue
            yield item
            last = item
    
    def sort_and_deduplicate(l):
        return list(uniq(sorted(l, reverse=True)))
    

    【讨论】:

    • +1 用于解释,因为在唯一化之前排序比其他方式更容易,并且您的答案不需要元素可转换为 tuple。然而,只有不可变类型是可散列的,这并不完全正确——只有不可变类型和a==b 暗示id(a)==id(b) 的可变类型是可散列的。 (我忘记了确切的措辞,但是发现措辞令人困惑的人对 SO 提出了多个问题……)
    • @abarnert 是的,说只有不可变类型是可散列的有点简化,因为它忽略了按部分状态比较/散列的对象。 (通过身份比较的对象仍然可以被认为是不可变的,只要它们的有用状态被它们的身份捕获 - 想想实习枚举和哨兵。)
    • 嗯,是的,但是 Python 文档明确讨论了通过身份进行比较的可变对象,因此认为这些对象真的应该被认为是不可变的,只会让文档中已经令人困惑的部分更加混乱。
    • @abarnert 你有这方面的参考吗?我能找到的最接近的是definition of hashable,但它没有明确谈论按身份比较的可变对象。 hashdict 的文档也没有帮助。
    • docs.python.org/2/reference/…,在字典下:“唯一不能作为键接受的值类型是包含列表或字典或其他通过值而不是对象标识进行比较的可变类型的值”。如果不存在通过对象标识进行比较的可变类型之类的东西,那么这种区分就没有必要,甚至没有意义。 IIRC,参考文献中再次有类似的文字,教程中也有一次。
    【解决方案3】:
        python 3.2
    
    
        >>>> from itertools import chain
        >>>> eg=sorted(list(set(list(chain(*eg)))), reverse=True)
            [7, 6, 5, 4, 3, 2, 1]
    
    
       ##### eg contain 2 list within a list. so if you want to use set() function
       you should flatten the list like [1, 2, 3, 4, 4, 5, 6, 7]
    
       >>> res= list(chain(*eg))       # [1, 2, 3, 4, 4, 5, 6, 7]                   
       >>> res1= set(res)                    #   [1, 2, 3, 4, 5, 6, 7]
       >>> res1= sorted(res1,reverse=True)
    

    【讨论】:

      【解决方案4】:

      设置删除重复项。为了做到这一点,该项目在集合中时不能更改。列表在创建后可以更改,并且被称为“可变”。你不能把可变的东西放在一个集合中。

      列表有一个不可变的等价物,称为“元组”。这就是您编写一段代码的方式,该代码获取一个列表,删除重复的列表,然后对其进行反向排序。

      result = sorted(set(map(tuple, my_list)), reverse=True)

      附加说明:如果一个元组包含一个列表,该元组仍然被认为是可变的。

      一些例子:

      >>> hash( tuple() )
      3527539
      >>> hash( dict() )
      
      Traceback (most recent call last):
        File "<pyshell#5>", line 1, in <module>
          hash( dict() )
      TypeError: unhashable type: 'dict'
      >>> hash( list() )
      
      Traceback (most recent call last):
        File "<pyshell#6>", line 1, in <module>
          hash( list() )
      TypeError: unhashable type: 'list'
      

      【讨论】:

      • 谢谢!!这里,结果是元组还是列表?
      • 这是一个元组列表;您必须将元素转换回列表。
      • @user1747696:转换回列表就像转换为元组一样简单:result = map(list, sorted(set(map(tuple, my_list)), reverse=True))。 (在某些时候,你会想把它分成多行,中间步骤的名称……)
      猜你喜欢
      • 2022-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-01
      • 2015-02-11
      • 2021-07-26
      • 2019-10-11
      • 2020-03-27
      相关资源
      最近更新 更多