在Ruby中将哈希值设置为另一个哈希值

时间:2012-07-16 20:13:50

标签: ruby hashtable

我想跟踪一些任意命名的字符串的计数,然后将计数重置为零。我的想法是做以下事情:

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,这与我想要的相反。如何实现所需的行为?

4 个答案:

答案 0 :(得分:5)

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

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

哈希的默认值:

new_hash = Hash.new(0)

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

new_hash["eggs"]  # -> 0

然后您可以添加计数:

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

完成后,只需致电

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"}

每次都会在key处创建一个新对象,因此对一个对象的更改不会产生波动:

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

答案 1 :(得分: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

答案 2 :(得分:2)

您正在修改单个哈希。

两个变量都引用相同的哈希值。当您更改散列中的项目时,两个引用都将反映该更改 - 因为它是相同的散列实例。

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

答案 3 :(得分:1)

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

请参阅https://stackoverflow.com/a/4157438/1118101

否则,您只需要为同一个哈希创建2个“指针”,而不是复制内容。

然后使用replace将克隆的内容复制回现有的哈希值。