【问题标题】:Why should dictionary keys be immutable?为什么字典键是不可变的?
【发布时间】:2013-03-04 13:33:11
【问题描述】:

有一个问题,为什么他们要求使用不可变对象作为字典中的键。

当我最近使用字典(显然不是为了哈希表的目的)将 Xml 节点对象作为键放置时,这个问题实际上出现在我的脑海中。然后我在使用过程中多次更新节点。

那么“使用不可变键”的真正含义是什么?

【问题讨论】:

  • 查看我对this question 的回答,我在其中详细描述了可变字典键的后果。
  • Dictionary 是一种散列数据结构。如果您更改了一个键,但它仍然占用数据结构中的相同槽,那么散列会中断吗?
  • this blog post 的确切问题标题是否为“必须”表示“应该”没有回答您的问题或出现在您的搜索结果中?
  • 例如:在一个非常具体和奇怪的要求中,我实现了一个 IDictionary。我已经通过大量的测试场景对其进行了测试。 XmlNodes 被添加和/或删除,但它仍然没有中断。

标签: c# dictionary key immutability


【解决方案1】:

当您将键插入哈希表时,哈希表会询问键的哈希码,并将其与键本身和相关值一起记住。当您稍后执行查找时,哈希表会向您查找的键询问其哈希码,并且可以非常快速地找到表中具有相同哈希码的所有键。

只要哈希表中的键在其生命周期中保持相同的哈希码就可以了——但如果它们是可变的(并且在插入哈希表后发生变异),那么通常哈希码会发生变化,此时您在搜索时将永远找不到该条目。

当然,这只适用于影响平等的突变。例如,如果您使用名称和生日对 Person 实体进行哈希处理,但由于某种原因,只有名称用于相等(因此在计算哈希码时仅使用名称),那么您可以插入 Person将其作为键放入哈希表中,更改其生日,以后仍然可以再次查找它,没有任何问题。

【讨论】:

  • 值得注意的是,由于XMLNode(问题中的情况)不会覆盖EqualsGetHashCode,它的平等概念是基于身份的,身份本质上是不可变的。虽然此类对象很少用作键,但在确实有用的情况下,它们作为键是安全的。
【解决方案2】:

字典类型是键和值之间的映射。映射将使用键的各种属性在内部字典存储中为其分配一个槽。在大多数情况下,它简单地将属性减少到 int 值。

如果键随时间变化,那么它的属性可能会开始映射到表中的不同索引。因此,该键将不再能够检索它最初在表中映射到的值。不可变类型完全避免了这种情况,因为它们永远不会改变。因此它们的映射始终是一致的

【讨论】:

  • 在什么情况下它不会将密钥减少为int 值?
  • @AllonGuralnek 如果字典被实现为二叉搜索树。在该实现中,您只需要知道不一定必须是 int 的相对顺序(尽管在绝大多数情况下都是这样做的)
  • 哦,你说的是一般意义上的,而我以为你说的是​​ BCL 中的实现。
  • @AllonGuralnek 正确。这个问题的原始版本没有指定语言/框架,因此我试图保持我的回答一般。
【解决方案3】:

字典根据键的哈希码将项目放入桶中。如果您添加一个项目,然后更改其密钥,您将无法再找到该项目。

如果使用新键值查找,字典会在不同的桶中查找,如果使用旧键值,字典会找到它所在的桶,但键不再匹配。

【讨论】:

    猜你喜欢
    • 2014-08-04
    • 2022-11-27
    • 1970-01-01
    • 1970-01-01
    • 2019-06-25
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多