ruby - 访问不存在的键时的多级哈希默认参数,如 h[1][1] += 1

标签 ruby hash hash-of-hashes

<分区>

我正在尝试创建 Hash-es 的 Hash。二级散列的值是一个默认为 0 的整数。我想做的是从一个空的散列开始,然后当我添加一个值时如果键不存在,应该添加它们的键具有默认值。

当我用一个简单的整数 Hash 尝试这个时,它工作正常:

irb(main):003:0> h = Hash.new(0)
=> {}
irb(main):004:0> h[1] += 1
=> 1
irb(main):005:0> p h
{1=>1}
=> nil
irb(main):006:0> h.keys.size
=> 1
irb(main):007:0>

h 现在有一个键,值为 1。完美。

但是当我的散列值是散列值时,它似乎不起作用:

irb(main):007:0> h = Hash.new(Hash.new(0))
=> {}
irb(main):008:0> h[1][1] += 1
=> 1
irb(main):009:0> p h
{}
=> nil
irb(main):010:0> h.keys.size
=> 0
irb(main):011:0>

我是不是做错了什么,或者我不能将散列的默认值设置为 Hash.new(0)

编辑:

根据下面的答案,我能够弄清楚我做错了什么。实际上,我能够找出我的想法有问题的地方。长话短说,h[1][1] 不会嵌套 Hash.new 调用,除非您给 Hash.new 一个 block 要调用的代码。表达式 h[1][1] += 1 的值如预期的那样是 1,但只有最里面的哈希被正确初始化。

我发布这个是因为虽然我上面的例子使用了二维散列,但我的实际问题使用了 3 维散列:

syms[级别][交换][符号] = 计数

该解决方案可能对遇到此问题的其他人有所帮助,所以这里是使它按照我想要的方式工作的代码:

irb(main):024:0> syms = Hash.new{|h1,k1| h1[k1] = Hash.new{|h2,k2| h2[k2] = Hash.new(0)}}
=> {}
irb(main):026:0> syms["level1"]["NYSE"]["IBM"] += 1
=> 1
irb(main):027:0> p syms
{"level1"=>{"NYSE"=>{"IBM"=>1}}}
=> nil
irb(main):028:0>

最佳答案

创建哈希时设置默认值的最常用方法是使用带有 block 参数的 Hash#new 函数:

h = Hash.new { |h, k| h[k] = Hash.new(0) }

您遇到的问题是您将默认值设置为对象指针而不是要执行的一段代码。也就是说,每次访问“外部”散列中的缺失值时,它都会返回指向完全相同 对象的指针。为了向自己证明这一点,试试这个:

>> h = Hash.new(Hash.new(0))
=> {}
>> h[1] === h[2]
=> true

因此您可以实际上为散列设置默认值,但这样做不会达到您想要的效果。递增 h[1][1] 实际上会更改默认散列本身,因为 h[1] 尚未初始化。

希望这对您有所帮助。

关于ruby - 访问不存在的键时的多级哈希默认参数,如 h[1][1] += 1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3576008/

相关文章:

ruby - Mechanize 和重定向( ruby )

PHP mysqli_connect : authentication method unknown to the client [caching_sha2_password]

perl - 如何用 perl 写得更好

ruby - 构建散列的散列以确定 ruby​​ 中的最大数值

ruby - 在 Ruby 中将嵌套哈希键从 CamelCase 转换为 snake_case

ruby - 有什么方法可以检测 Ruby 中的属性更改吗?

ruby-on-rails - 将一个巨大的字符串作为参数传递给 Sidekiq worker 是个好主意吗?

c++ - 知道为什么 QHash 和 QMap 返回 const T 而不是 const T& 吗?

ruby-on-rails - 如何在哈希中创建哈希

ruby - 在 Sinatra 的自定义错误 block 中设置状态代码