首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否从no-op中的集合中删除已修改的对象?

是否从no-op中的集合中删除已修改的对象?
EN

Stack Overflow用户
提问于 2012-04-28 15:05:42
回答 1查看 146关注 0票数 4

请参见下面的示例

代码语言:javascript
复制
require "set"
s = [[1, 2], [3, 4]].to_set # s = {[1, 2], [3, 4]}
m = s.max_by {|a| a[0]} # m = [3, 4]
m[0] = 9 # m = [9, 4], s = {[1, 2], [9, 4]}
s.delete(m) # s = {[1, 2], [9, 4]} ?????

这与数组的行为不同。(如果我们删除.to_set,我们将得到预期的s = [[1, 2]]。)这是一个bug吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-04-28 15:34:36

是的,这是一个bug,或者至少我会称它为bug。有些人会称这是“一个意外泄露给外界的实现细节”,但这只是一种花哨的城市男孩对bug的说法。

这个问题有两个主要原因:

  1. 您在Set不知情的情况下修改Set的元素。
  2. 标准Set被实现为哈希。

其结果是,您在Hash不知道的情况下修改了内部Hash的键,这会使可怜的Hash变得不再真正知道它拥有什么键。哈希类有一个rehash method

重新散列hsh

根据每个键的当前哈希值重新生成哈希。如果key对象的值在插入后发生了更改,此方法将重新索引hsh。

A= "a","b“c= "c","d”h={a => 100,c => 300 } ha #=> 100 a= "z“ha #=> nil h.rehash #=> {"z","b"=>100,"c","d"=>300} ha #=> 100

请注意rehash文档附带的示例中的有趣行为。散列使用键kk.hash值来跟踪事物。如果您有一个数组作为键,并且您更改了数组,那么您也可以更改数组的哈希值;结果是hash仍然将该数组作为键,但不能找到该数组作为键,因为它将在存储桶中查找新的hash值,但该数组将在存储桶中查找旧的hash值。但是,如果你rehash散列,它将突然能够再次找到它的所有密钥,衰老消失了。对于非数组的键,也会出现类似的问题:你只需要改变键的哈希值,使其哈希值发生变化,包含该键的哈希值就会变得混乱,并在丢失时四处游荡,直到你rehash它为止。

Set class在内部使用散列来存储其成员,并将成员用作散列的键。所以,如果你改变了一个成员,集合将会变得混乱。如果Set有一个rehash方法,那么你可以通过用rehash把Set打在头上来解决这个问题;可惜,Set中没有这样的方法。然而,你可以在你自己的插件中添加:

代码语言:javascript
复制
class Set
  def rehash
    @hash.rehash
  end
end

然后,您可以更改密钥,在集合上调用rehash,您的delete (以及各种其他方法,如member?)将正常工作。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10361400

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档