【问题标题】:Are sets ordered like dicts in python3.6集合是否像 python3.6 中的 dicts 一样排序
【发布时间】:2018-01-16 19:48:23
【问题描述】:

由于 Python 3.6 中 dict 实现的更改,现在默认排序。 sets 现在也保持秩序吗?

我找不到任何关于它的信息,但由于这两种数据结构在它们的底层工作方式上非常相似,我认为可能是这种情况。

我知道dicts 不会在所有情况下都被订购,但大多数情况下都是如此。如 Python 文档中所述:

这个新实现的顺序保留方面被认为是一个实现细节,不应依赖

【问题讨论】:

标签: python set python-3.6 cpython python-internals


【解决方案1】:

不,sets 仍然是无序的。

您可以通过显示一个应该具有“明确定义的哈希顺序”的set 来验证这一点1 以确保我们不会意外得到一个看起来有序但实际上的set实际上不是:

>>> a_set = {3,2,1}
>>> a_set
{1, 2, 3}
>>> list(a_set)
[1, 2, 3]

如果已订购,您会期望 {3, 2, 1} 和 [3, 2, 1] 作为示例的结果。

虽然dicts 实际上是有序的(相同的例子只是稍作修改):

>>> a_dict = {3: 3, 2: 2, 1:1}
>>> a_dict
{3: 3, 2: 2, 1: 1}
>>> list(a_dict)
[3, 2, 1]

1 “定义明确的哈希顺序”:

对于满足0 <= integer < sys.hash_info.modulus 的整数,hash 只是数字本身。这意味着如果集合是根据散列“基于”排序(而不是基于插入“时间”排序)并且散列值不冲突(这就是我使用小数字和仅相差一个的数字的原因)顺序应该是确定性的,因为它们占据了集合中彼此相邻的插槽:

  • 从小到大
  • 或从特定值到最高值,然后从最小值到特定值。如果集合中的下一个(在相邻的意义上)空闲槽位是第一个空闲槽位,则会发生这种情况。

以后者为例:

>>> a_set = {6,7,8,9}
>>> a_set
{8, 9, 6, 7}

【讨论】:

  • Negative ints 也对自己进行哈希处理(-1 除外),尽管我不确定确切的下限是多少
  • @Chris_Rands 是的,但是因为 -1 和 -2 都哈希到 -2 有一个冲突。:)
  • 是的,-1 这样做是因为它是 C 语言中的错误代码;我相信边界是(sys.maxsize // 4) - 1,至少这是Martijn Pieters之前告诉我的
  • 很高兴知道。但如果想在hash 期间捕获错误,这是有道理的。我还找到了最大值。这是sys.hash_info.modulus。 :)
【解决方案2】:

sets 在 Python 3.6 中没有排序,甚至没有作为 CPython 实现细节。一个简单的例子说明了这一点:

>>> import string
>>> string.digits
'0123456789'
>>> set(string.digits)
{'7', '0', '2', '8', '6', '9', '1', '5', '4', '3'}

Python 3 docs 对此很清楚:

集合是没有重复元素的无序集合。

【讨论】:

  • 但dict 上的文档也说“最好将字典视为 无序 键:值对集,并要求键是唯一的(在一本字典中)。” (source)。这只是语言规范,可以订购实现...
  • @MSeifert “最好考虑”是我认为的关键措辞,set 文档没有这样的警告
  • 我认为这只是“绒毛”(或包括在内,因为 PyPy 长期以来一直有一个有序的字典)。但是,就像我说的,这只是语言规范。这并不意味着实现可以以有序的方式实现它(即使用存储桶或类似方式)。
  • 评论已过时,现在从文档的该部分中删除了“无序”一词。
  • 我认为在 python 3.6 文档中的措辞保持不变docs.python.org/3.6/tutorial/datastructures.html#dictionaries
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-27
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
  • 1970-01-01
  • 2014-05-28
相关资源
最近更新 更多