AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79352669
Accepted
Stefan Pochmann
Stefan Pochmann
Asked: 2025-01-13 23:24:07 +0800 CST2025-01-13 23:24:07 +0800 CST 2025-01-13 23:24:07 +0800 CST

为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同?

  • 772

集合是无序的,或者说它们的顺序是一个实现细节。我对这个细节很感兴趣。我看到了一个让我惊讶的案例:

print({2, 3, 10})
x = 2
print({x, 3, 10})

输出(在线尝试!):

{3, 10, 2}
{10, 2, 3}

尽管相同的元素以相同的顺序写入,但它们的排序却不同。这是怎么发生的?这是故意为之吗?例如,为了优化查找速度?

我的sys.version和sys.implementation:

3.13.0 (main, Nov  9 2024, 10:04:25) [GCC 14.2.1 20240910]
namespace(name='cpython', cache_tag='cpython-313', version=sys.version_info(major=3, minor=13, micro=0, releaselevel='final', serial=0), hexversion=51183856, _multiarch='x86_64-linux-gnu')
python
  • 1 1 个回答
  • 780 Views

1 个回答

  • Voted
  1. Best Answer
    ShadowRanger
    2025-01-13T23:55:52+08:002025-01-13T23:55:52+08:00

    它是由以下几个因素决定的:

    1. 哈希桶冲突 - 对于最小set大小,8(CPython 的实现细节)2和10在它们的缩减哈希码上发生冲突(同样是实现细节,是2和10;mod 8,它们都是 2)。无论哪个先插入,都将“获胜”并获得桶索引 2,另一个将被探测操作移动。探测操作(同样是 CPython 实现细节)首先检查线性相邻的桶是否有空桶(因为它通常会找到一个,而更好的内存局部性可以提高缓存性能),并且只有在没有找到空桶时,它才会开始随机跳跃算法来查找空桶(它不能进行纯线性探测,因为这会很容易触发将set操作从摊销平均情况更改O(1)为的病态情况O(n))。

    2. 编译时优化:在现代 CPython 中,长度至少为三个元素的常量文字的sets 和s 在编译时被构造为不可变容器(分别为和)。在运行时,它会构建一个空的/ ,然后使用不可变容器对其进行s/ ,而不是对每个元素执行单独的加载和s/ 。这意味着当您使用 构建时,您实际上是在执行(使用从缓存中提取的 ),而是通过在堆栈上加载 和 来构建的,然后作为单个操作构建。listfrozensettuplesetlistupdateextendaddappends = {2, 3, 10}s = set()s.update(frozenset({2, 3, 10}))frozensets = {x, 3, 10}x310set

    这两个意味着您实际上是以不同的方式构建它;{x, 3, 10}插入2,然后3,然后10,因此存储桶2和3已填满,并10重新定位(探测策略显然将其放在存储桶0或1中,在存储桶之前2)。当您执行时{2, 3, 10},在编译时它会创建一个frozenset({3, 10, 2}),然后在运行时,它会创建空的set,然后通过迭代来更新它frozenset,这已经对元素进行了重新排序,因此现在它们不再按2、、顺序添加,并且“首选”存储桶的竞争由不同的元素赢得。310

    综上所述,的行为{x, 3, 10}等同于:

    s = set()
    s.add(x)
    s.add(3)
    s.add(10)
    

    可以预见的是,它将桶 2 和 3 分配给2它们3自己,同时10被转移到桶 0 或 1。

    相比之下,{2, 3, 10}构建一个(注意:在转换为之后,frozenset({3, 10, 2})它的顺序是这样的;如果您尝试运行该行,您会看到不同的顺序),然​​后用它创建一个空的。有一个优化的代码路径可以从另一个/填充一个空的,它只是直接复制内容(而不是逐个迭代和插入),因此缓存中的顺序在从它创建的每个缓存中都保留,就像您运行:frozensetprintupdatesetsetsetfrozenset{3, 10, 2}frozensetset

    s = set()
    s.update(frozenset({2, 3, 10}))
    

    但性能更佳(因为frozenset在编译时创建一次,并且每次set初始化时都廉价地加载)。

    • 19

相关问题

  • 如何将 for 循环拆分为 3 个单独的数据框?

  • 如何检查 Pandas DataFrame 中的所有浮点列是否近似相等或接近

  • “load_dataset”如何工作,因为它没有检测示例文件?

  • 为什么 pandas.eval() 字符串比较返回 False

  • Python tkinter/ ttkboostrap dateentry 在只读状态下不起作用

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve