【问题标题】:Add a dictionary to a `set()` with union使用 union 将字典添加到`set()`
【发布时间】:2016-03-09 22:53:19
【问题描述】:

我刚刚遇到了一些有趣的问题,我想问一下。

将字典添加到set,我曾假设该字典将作为完整字典添加,但事实并非如此。仅添加键:

dicty = {"Key1": "Val1", "Key2": "Val2"}
setunion = set()
setunion.union(dicty)
=> set(['Key2', 'Key1'])

当您尝试使用 set.add() 添加它时,您会收到错误:

setadd = set()
setadd.add(dicty)
Traceback (most recent call last):
  File "python", line 1, in <module>
TypeError: unhashable type: 'dict'

显然,这种行为与列表非常不同:

   listy = []
   listy.append(dicty)
   listy
=> [{'Key2': 'Val2', 'Key1': 'Val1'}]

In the docs 它说集合是 hashable 对象的无序集合,这暗示了上述一些问题。

问题

这里发生了什么?集合项目必须是可散列的,很明显这与为什么我只使用.union() 将键添加到集合中,但为什么.add() 出现错误?

列表中集合的行为差异背后是否存在一些可用性原因?

Python(或库)中是否存在本质上类似于列表但只保留唯一项的数据类型?

【问题讨论】:

  • 所以你想要一个保持顺序但不允许重复的结构?
  • 为什么你认为union 是向集合添加东西的方式? union 表示“构造一个新集合,将参数的 元素 添加到新集合中”。就像extend 用于列表,但没有到位。
  • @senshin 我什至没有考虑订购问题。我更想知道允许添加任何对象但不允许(或“吸收”)重复的任何结构。
  • @NotAnAmbiTurner:这不是唯一的区别。 add 没有真正的全新套装版本。 union 的变异版本是 union_update
  • @user2357112 噢噢噢噢。说得通。我正在学习 python,我在hackerrank 上胡闹,这在新概念方面非常好,但在避免混淆方面可能不是最好的。

标签: python dictionary set hashable


【解决方案1】:

不,根据定义,这是不可能的。哈希表(如dicts 和sets)进行查找的方式与数组(如lists)进行查找的方式基本不同。逻辑错误是,如果你有一个只保存重复的数据类型,如果你将其中一个元素改变为非唯一的会发生什么?

a, b = [0], [0, 1]
s = SpecialSet(a, b)
a.append(1)  # NOW WHAT?!

如果你想给一个集合添加一个字典,你可以添加它的dict.items 视图(实际上只是一个元组列表),但是你必须先转换成元组。

a = {1:2, 3:4}
s = set()
s.add(tuple(a.items()))

然后你必须重新转换为 dict ,一旦它离开集合才能取回字典

for tup in s:
    new_a = dict(tup)

PEP416 中提出了一个内置的frozendict 类型,但最终被拒绝。

【讨论】:

  • @NotAnAmbiTurner:但是您的 SpecialSet 中有重复项。
  • @user2357112 哦,我明白了。好的谢谢。让我试着说得更清楚。
  • 好吧,也许我不是很清楚。我不想在 SpecialSet 中存储一个可变对象,我想我正在寻找的是SpecialSet 在传入一个可变对象时创建它自己的实例的能力。人们是否使用这样的可变性来存储另一个对象内的东西,并在它的容器内对其进行变异?对我来说,这似乎......错了......但我是初学者。难道你不想得到价值,把它弄乱,然后重新添加到容器中吗?
  • 所以我想我的想法是SpecialSet.__init__ 会复制并存储每个值,首先确保它们是唯一的。
  • @NotAnAmbiTurner 我完全不确定你在说什么。这与set 所做的有什么不同?
【解决方案2】:

使用set.union(),请求将方法的参数的元素 添加到集合中,而不是对象本身。遍历字典会为您提供键。如果您在列表、元组或字符串上使用 set.union(),您会得到类似的结果,其中的 contents 会添加到集合中:

>>> s = {42}
>>> s.union('foo')
set([42, 'o', 'f'])

添加了单字符串'o''f',而不是字符串'foo'

您不能将字典添加到集合中,因为它们是可变的;集合仅支持存储可散列的对象,而对象可散列的要求之一是它们是不可变的。

【讨论】:

  • nit:你可以在可变对象上实现__hash__
  • @AdamSmith:是的,违反了要求。 Python 让你用那只脚射击自己。
  • 我的观点更多地与行为有关。对我来说很奇怪,您可以将字典作为字典添加到列表中,但不能添加到集合中。我最初认为集合的设计本质上是一个 list 的 unqiue 项目,但似乎不止于此。
  • @NotAnAmbiTurner setdict 的共同点比 list 更多。由于 list 按索引引用,它并不关心其中的内容。一个set(和一个dict的键)通过hash引用,应该和value密不可分。
猜你喜欢
  • 2017-05-31
  • 1970-01-01
  • 1970-01-01
  • 2017-10-11
  • 1970-01-01
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
  • 2022-01-11
相关资源
最近更新 更多