【问题标题】:How to work with types in a list correctly如何正确使用列表中的类型
【发布时间】:2021-06-06 16:58:13
【问题描述】:

我写了一个函数,用集合替换列表中的所有元素

def get_set(arr):
  return list(map(lambda x: set(x),arr))

通过例子来工作

A=[(0, 3), (0, 4), (3, 4)]
A=get_set(A)

我们得到

A=[{0, 3}, {0, 4}, {3, 4}]

但如果我使用 thif 函数为例

B=[({0, 3}, {0, 4}), ({0, 3}, {3, 4}), ({0, 4}, {3, 4})]
get_set(B)

我收到一个错误

<ipython-input-50-10fd7735b9ce> in <lambda>(x)
      1 def get_set(arr):
----> 2   return list(map(lambda x: set(x),arr))

TypeError: unhashable type: 'set'

如何修复我的代码并获取?

B=[{{0, 3}, {0, 4}}, {{0, 3}, {3, 4}}, {{0, 4}, {3, 4}}]

【问题讨论】:

  • 请注意:lambda x: set(x)set 之间没有实际区别。
  • 简短的回答是你不能:集合是可变的,因此不可散列。

标签: python python-3.x list set


【解决方案1】:

简短的回答是错误会告诉你一切:setdictlist 等元素是不可散列的,因为它们是可变的。这意味着你不能用它们来构建一个集合。

但这当然不是故事的结局。只要您以对象模型允许的方式明确地分配含义,您就可以有意义地构建一组您想要的任何东西。例如,您可以将不可散列的类型映射到返回合适的替代或包装器的函数:

type_map = {
    list: tuple,
    set: frozenset,
    dict: lambda x: tuple(x.items()),
    bytearray: bytes,
}

如果dict 仅在您计划对type(x) == y 形式进行类型检查而不是使用更惯用的isinstance 时才完全有用。但是,即使在后一种情况下,dict 也是一个不错的配对容器。

更通用的解决方案可能类似于

def wrap_type(x):
    """
    Attempt to turn `x` into a hashable type using registry in `type_map`.

    The result is not guaranteed to be hashable.
    """
    for t, w in type_map.items():
        if isinstance(x, t):
            return w(x)
    return x

def transform_set(i):
    return set(wrap_type(x) for x in i)

def get_set(i):
    return list(map(transform_set, i))

这个实现有(至少)一个缺陷:wrap_type 不是递归的。它可能会正确地将所有列表转换为元组,但如果任何元素不可散列,则不会使结果可散列。该问题仅适用于某些类型,例如listdict,甚至tuple,但不适用于bytearrayset

您可以通过实现type_map 来包含递归来避免这种情况:

from collections.abc import Sequence, Mapping, Set

def wrap_seq(s):
    return tuple(wrap_type(x) for x in s)

def wrap_map(m):
    return tuple((k, wrap_type(v)) for k, v in m.items())

type_map = {
    Sequence: wrap_seq,
    Set: frozenset,
    Mapping: warp_map,
}

【讨论】:

    【解决方案2】:

    B 中的每个元素都是集合的元组。您可以使用可散列的frozenset。 因此每个元素都可以是可散列的,并且可以转换为集合。

    def get_set(arr):
      return list(map(set, arr))
    
    B=[
      (frozenset([0, 3]), frozenset([0, 4])),  
      (frozenset([0, 3]), frozenset([3, 4])), 
      (frozenset([0, 4]), frozenset([3, 4]))  
     ]
    B=get_set(B)
    print(B)
    

    输出

    [set([frozenset([0, 4]), frozenset([0, 3])]), set([frozenset([3, 4]), frozenset([0, 3])]), set([frozenset([3, 4]), frozenset([0, 4])])]
    

    【讨论】:

      【解决方案3】:

      def get_set(arr): 返回列表(地图(lambda x:set(x),arr)) 它通过示例工作

      A=[(0, 3), (0, 4), (3, 4)] A=get_set(A) 我们得到

      A=[{0, 3}, {0, 4}, {3, 4}] 但是如果我使用 thif 函数,例如

      B=[({0, 3}, {0, 4}), ({0, 3}, {3, 4}), ({0, 4}, {3, 4})] get_set(B) 我收到一个错误

      在 (x) 1 def get_set(arr): ----> 2 返回列表(map(lambda x: set(x),arr))

      TypeError: unhashable type: 'set'

      【讨论】:

        猜你喜欢
        • 2012-02-21
        • 2011-03-18
        • 2021-09-25
        • 1970-01-01
        • 2011-01-04
        • 1970-01-01
        • 2022-06-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多