在Ruby中复制哈希

时间:2015-07-11 23:21:28

标签: ruby hash

我正在尝试使用默认值的另一个哈希来初始化ruby中的哈希值。我想要一份深刻的副本,但我似乎只能得到一份浅色的副本。

以下是一个例子:

DEFAULT_HASH = { a: 0, b: 1 }.freeze
my_hash = DEFAULT_HASH.dup
my_hash[:a] = 4 

现在“my_hash”和DEFAULT_HASH中a的值是4.我只想改变哈希值中的值。

我也尝试了其他方法:

my_hash = {}.merge DEFAULT_HASH

my_hash.merge! DEFAULT_HASH

所有这些产生相同的效果。实现这种初始化的最佳方法是什么。我也在使用嵌套哈希,这增加了一些复杂性。

即。我的DEFAULT_HASH看起来像:

DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }

这会影响如何做到吗?

编辑: 嵌套哈希案例

DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }
=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}} 
a=DEFAULT_HASH.dup
=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}} 
a[:b][:a]=12
=> 12 
DEFAULT_HASH
=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>12, :b=>1}} 

3 个答案:

答案 0 :(得分:3)

您可以使用Marhal::dumpMarshal::load轻松创建自己的深度复制方法:

def deep_dup(obj)
  Marshal.load(Marshal.dump(obj))
end

obj可以是任何Ruby对象(例如,数组和散列的嵌套混合)。

h = { a: { b: { c: { d: 4 } } } }

g = deep_dup(h)         #=> {:a=>{:b=>{:c=>{:d=>4}}}}

g[:a][:b][:c][:d] = 44  #=> 44
g                       #=> {:a=>{:b=>{:c=>{:d=>44}}}} 
h                       #=> {:a=>{:b=>{:c=>{:d=>4}}}} 

对于你的例子:

DEFAULT_HASH = { a: { a:1, b:2 }, b: { a:2, b:1 } }
  #=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}} 
h = deep_dup(DEFAULT_HASH)
  #=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}} 
h[:b][:a] = 12
  #=> 12
h #=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>12, :b=>1}}
DEFAULT_HASH
  #=> {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}} 

答案 1 :(得分:2)

对于@ pjs来说,Hash#dup将为散列的顶级“做正确的事”。但是对于嵌套哈希,它仍然会失败。

如果您愿意使用某个宝石,请考虑使用deep_enumerable,这是我为此目的编写的一个宝石(等等)。

DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }
dupped = DEFAULT_HASH.dup

dupped[:a][:a] = 'updated'

puts "dupped:       #{dupped.inspect}"
puts "DEFAULT_HASH: #{DEFAULT_HASH.inspect}"


require 'deep_enumerable'
DEFAULT_HASH = { a:{a:1, b:2}, b:{a:2, b:1} }

deep_dupped = DEFAULT_HASH.deep_dup
deep_dupped[:a][:a] = 'updated'

puts "deep_dupped:  #{deep_dupped.inspect}"
puts "DEFAULT_HASH: #{DEFAULT_HASH.inspect}"

输出:

dupped:       {:a=>{:a=>"updated", :b=>2}, :b=>{:a=>2, :b=>1}}
DEFAULT_HASH: {:a=>{:a=>"updated", :b=>2}, :b=>{:a=>2, :b=>1}}

deep_dupped:  {:a=>{:a=>"updated", :b=>2}, :b=>{:a=>2, :b=>1}}
DEFAULT_HASH: {:a=>{:a=>1, :b=>2}, :b=>{:a=>2, :b=>1}}

或者,您可以尝试以下方式:

def deep_dup(h)
  Hash[h.map{|k, v| [k,
    if v.is_a?(Hash)
      deep_dup(v)
    else
      v.dup rescue v
    end
  ]}]
end

注意,这最后一个函数远不及deep_enumerable测试。

答案 2 :(得分:-1)

.freeze给出了以下结果:

irb(main):001:0> DEFAULT_HASH = { a: 0, b: 1 }
=> {:a=>0, :b=>1}
irb(main):002:0> my_hash = DEFAULT_HASH.dup
=> {:a=>0, :b=>1}
irb(main):003:0> my_hash[:a] = 4
=> 4
irb(main):004:0> my_hash
=> {:a=>4, :b=>1}
irb(main):005:0> DEFAULT_HASH
=> {:a=>0, :b=>1}