Ruby:散列键的属性

时间:2011-07-08 08:30:53

标签: ruby

我将粘贴一个我尝试的简单示例,以便那些阅读此内容的人会清楚。

irb(main):001:0> h =  { }
=> {}
irb(main):002:0> a=[1,2,3]
=> [1, 2, 3]
irb(main):003:0> a.object_id
=> 69922343540500


irb(main):004:0> h[a] = 12          #Hash with the array as a key
=> 12
irb(main):005:0> a << 4             #Modified the array
=> [1, 2, 3, 4]
irb(main):006:0> a.object_id        #Object id obviously remains the same.
=> 69922343540500
irb(main):007:0> h[a]               #Hash with the same object_id now returns nil.
=> nil
irb(main):008:0> h                  #Modified hash
=> {[1, 2, 3, 4]=>12}
irb(main):009:0> h[[1,2,3,4]]       #Tried to access the value with the modified key -
=> nil


irb(main):011:0> h.each { |key,value| puts "#{key.inspect} maps #{value}" }
[1, 2, 3, 4] maps 12
=> {[1, 2, 3, 4]=>12}

现在,当我遍历哈希时,可以识别密钥和值之间的映射。

有人可以解释一下ruby hash的这种行为以及散列键的属性是什么。

1)正如我上面提到的,object_id没有改变 - 那么为什么值设置为nil。

2)是否有任何可能的方法,以便我可以从散列'h'返回值'12',因为上面提到的h [[1,2,3,4]]返回nil。

4 个答案:

答案 0 :(得分:8)

这是因为密钥在使用时不应更改其值。如果值发生变化,我们应该根据其当前值重建哈希值。查看Ruby API rehash方法。您可以通过在更改密钥后重新重新生成哈希来获取值,如下所示:

irb(main):022:0> h.rehash
=> {[1, 2, 3, 4]=>12}
irb(main):023:0> h[a]
=> 12

答案 1 :(得分:1)

使用#eql?方法检查哈希键,由于[1, 2, 3]不是.eql?[1, 2, 3,4],因此哈希查找的结果会有所不同。

如果语义不适合你,也许你想使用Array之外的其他内容作为Hash密钥?

答案 2 :(得分:1)

ruby hash api提供了答案:密钥在用作密钥时不应更改其值

我猜实习生为a计算哈希并用于快速查找(因为密钥不应该改变,哈希总是相同的)。所以,当你执行h[a]时,它找不到匹配项([1,2,3] .hash!= [1,2,3,4] .hash),当你执行h[[1,2,3]]时哈希匹配,但对象不匹配([1,2,3]!= [1,2,3,4])。

修复是使用object_id作为键,因为它不会更改,h[a.object_id] = 12将在更改时返回12。当然,这有一个缺点,即h[[1,2,3].object_id]不会返回12。

答案 3 :(得分:1)

Stefaan Colman的答案更为彻底,但有几点意见:

Ruby使用Object#hash方法来散列对象。

此时您可以像a.delete(4); h[a]一样退出,[1,2,3]也可以再次用作关键字。