2015-07-11 74 views
3

我想通过使用另一个哈希与默认值来初始化红宝石哈希。我想要一个深层的副本,但我似乎只能得到一个浅拷贝。在Ruby中复制哈希

下面是一个例子:

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

现在的在“my_hash”,并在DEFAULT_HASH值为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}} 
+0

什么版本的Ruby是你这样做?我无法重现你的行为。 – Makoto

+0

这是与JRuby 1.7.19和Ruby 2.2.0 – System123

+0

我使用的是Ruby的类似版本,而我看不到相同的东西。你确定* DEFAULT_HASH正在改变吗? – Makoto

回答

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以及测试。

+0

完美,我不介意为此使用宝石。这是我项目中相当重要的一部分。 – System123

-1

.freeze ING得出以下结果:

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} 
+0

不使用嵌套散列时,请参阅编辑 – System123

3

您可以轻松创建自己的深DUP方法,使用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}}