2015-07-11 76 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}}