2012-07-16 147 views
5

我想跟踪一些任意命名的字符串的计数,然后将计数重置为零。我的想法是要做到以下几点:在红宝石中设置哈希等于另一个哈希

reset_hash={"string1"=>0,"string2"=>0,"string3"=>0} 
=> {"string1"=>0, "string2"=>0, "string3"=>0} 

new_hash = reset_hash 
=> {"string1"=>0, "string2"=>0, "string3"=>0} 

new_hash["string1"]=1 
new_hash["string3"]=1 
new_hash 
=> {"string1"=>1, "string2"=>0, "string3"=>1} 

...

现在我想重置回new_hash到reset_hash:

new_hash = reset_hash 
=> {"string1"=>1, "string2"=>0, "string3"=>1} 
reset_hash 
=> {"string1"=>1, "string2"=>0, "string3"=>1} 

这到底是怎么回事?看起来reset_hash实际上已经设置为new_hash,这与我想要的相反。我如何实现所需的行为?

回答

5

当你有一个变量指向一个对象时,你实际上只是对该对象的引用。如果a和b都指向散列{1 => 3,“foo”=> 54},则更改a或b会改变另一个。

但是,您可以使用两种方法的组合来制作您想要的内容。

的散列的默认值:

new_hash = Hash.new(0) 

这给了未使用的值的默认值为0:

new_hash["eggs"] # -> 0 

可以再加入数:

new_hash["string1"] += 1 # => 1 

当你're done just call

new_hash.clear # => {} 

和你的哈希将被重置,但新的访问将仍然默认为0。

请注意,如果您设置的默认值的类型不是数字对象的你或许可以改变的事情,由于上面提到的整个参考问题。

irb(main):031:0> b = Hash.new("Foo") #=> {} 
irb(main):032:0> b[3] #=> "Foo" 
irb(main):033:0> b[33] #=> "Foo" 
irb(main):034:0> b[33].upcase! #=> "FOO" 
irb(main):035:0> b[3] # => "FOO" 

要解决这个问题,你可以通过一个块给你凑:

h = Hash.new {|hash, key| hash[key] = "new default value"} 

这造成在每次密钥生成新的对象,所以改变一个不会波及:

d = Hash.new{ |hash,key| hash[key] = "string"} #=> {} 
d[3] # => "string" 
d[3].upcase! #=> "STRING" 
d[5] #=> "string" 
+0

谢谢!非常翔实的答案。 – 2012-07-17 20:53:49

2

您正在修改单个散列。

这两个变量引用相同的散列。当您更改散列中的项目时,两个引用都会反映该更改–,因为它是相同的散列instdance。

也许你想先复制散列?如果你这样做,并且你有一个复杂对象的散列,你还需要调查浅与深拷贝/克隆。

+0

我以为我在复制散列。那么我该如何正确地做到这一点? – 2012-07-16 20:22:34

+0

您正在复制*参考*到散列;你需要使用['clone'(docs)](http://apidock.com/ruby/Object/clone),注意注意事项。有很多方法可以进行深度克隆,包括编组/解组对象。 – 2012-07-16 20:24:41

1

您需要使用克隆来制作副本。

https://stackoverflow.com/a/4157438/1118101

否则,你只能创造200“指针”,以相同的散列,而不是将内容复制。

然后使用replace将克隆的内容复制回现有的散列。

+0

明白了。谢谢! – 2012-07-16 20:24:40

5

正如其他人提到你必须使用clone。你的任务应该是这样的:

reset_hash={"string1"=>0,"string2"=>0,"string3"=>0} 
new_hash = reset_hash.clone 

new_hash["string1"]=1 
new_hash["string3"]=1 
new_hash 

new_hash = reset_hash.clone 
reset_hash