【问题标题】:Why is Python's set() sorting a list in some cases?为什么 Python 的 set() 在某些情况下会对列表进行排序?
【发布时间】:2022-01-02 16:59:02
【问题描述】:

我对这个示例中 Python 的 set() 的行为感到困惑:

random_number_list = [randint(1, 10) for _ in range(10)]
# This will be sorted!
unique_numbers = set(random_number_list)

print(
    f"random_number_list/unique_numbers with same upper bound for randint() and range():\n{random_number_list=}\n{unique_numbers=}\n"
)

random_number_list = [randint(1, 100) for _ in range(10)]
# This will not be sorted.
unique_numbers = set(random_number_list)

print(
    f"random_number_list/unique_numbers with different upper bound for randint() and range():\n{random_number_list=}\n{unique_numbers=}\n"
)

如果列表的长度和randint() 的上限相同,则set() 似乎正在对random_number_list 进行排序:

➜  ch-2 python --version
Python 3.10.0
➜  ch-2 python find_k_smallest.py 
random_number_list/unique_numbers with same upper bound for randint() and range():
random_number_list=[10, 1, 2, 5, 5, 7, 8, 8, 2, 8]
unique_numbers={1, 2, 5, 7, 8, 10}

random_number_list/unique_numbers with different upper bound for randint() and range():
random_number_list=[35, 1, 17, 26, 17, 74, 26, 11, 44, 13]
unique_numbers={1, 35, 74, 11, 44, 13, 17, 26}

docs 状态:

集合对象是不同的可散列对象的无序集合。

这里发生了什么?为什么set() 在某些情况下对random_number_list 进行排序而不在其他情况下排序?

编辑这些问题都没有解决我的问题:

【问题讨论】:

  • 为什么会出现这个问题?
  • 我不认为这是一个问题,我只是不明白为什么会这样,希望有人能启发我。
  • 如果它发生在“某些情况下而不是其他情况下”,那么文档就是在告诉您真相,即使它可能发生,您也不应该指望订购。
  • 集合通常是无序的(并不意味着它是严格无序的)。顺序可能会因实施而异。

标签: python list random set


【解决方案1】:

真正回答你的问题。集合的许多实现使用类似于哈希表的实现。根据该哈希值对项目进行哈希处理并放入“数组”中。

请注意,对于小整数,hash(x) == x。所以 1 会进入插槽 1,2 会进入插槽 2,3 会进入插槽 3,依此类推。然后,当读取元素时,您会从字面上对元素进行排序。

但是,如果您的整数大于数组大小,那么它们在数组中的位置将以数组大小为模。它们将不再被排序。

同样,我还没有真正研究过 Python 实现。这只是对可能发生的事情的一种可能解释。

【讨论】:

  • 没有一个“Python 实现”,有好几个,所以查看其中任何一个都不会告诉您任何可以概括的信息。
  • 这很有启发性,谢谢!它也与我所看到的一致。
  • @martineau。我同意没有单一的“Python 实现”,但我认为我们可以同意 CPython 是最常用的实现。 CPython 实现的工件(例如有序字典)有时会成为标准的一部分。是的,CPython 中集合的实现似乎与我预期的差不多。不,OP 不应该依赖被排序的集合。
【解决方案2】:

“无序”并不意味着“未排序”。这意味着没有试图提供任何特定的订单;从实现中退出的顺序可能是也可能不是排序顺序。

【讨论】:

  • 对。但每次当我转换为setlist 的大小与填充listrandint() 的上限相关时,它 排序的。这就是让我感到困惑的部分。对于这种情况,一定有一些东西在订购set,我只是不确定这是一个已知的属性还是看起来是一个奇怪的实现怪癖。
  • 这是一个暗示怪癖,特别的怪癖是集合基于哈希表,哈希值是整数本身,并且您没有使用任何大于哈希表大小的整数.至少在我的机器上,找到一个排序的集合花了大约 2 秒:set([1000000000000000000, 2]).
  • 正确,并非所有集合都已排序。我也在我的例子中证明了这一点。但是,某些集合总是排序。哈希表的解释是有道理的,我现在正在研究它。我没有 CS 背景,但我目前正在学习 CS 主题,所以这非常有启发性!
【解决方案3】:

你在评论中写道:

我很好奇为什么set() 有时会在list 的大小与randint() 的边界相关时对其成员进行排序。

这是一个应用程序不应该关心的实现细节,即使在 Python 3.7(和 3.10)中,sets 也是documented as "unordered collection[s]"。例如,您可以查找source code of CPython 以找出how sets are implemented in CPython

另见:

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 2012-08-02
  • 1970-01-01
  • 2018-08-27
  • 2016-01-27
  • 2017-10-09
相关资源
最近更新 更多