我试图通过使用另一个具有默认值的哈希来初始化 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}}
就@pjs 的观点而言,
Hash#dup
将为哈希的顶层“做正确的事情”。然而,对于嵌套哈希,它仍然失败。
如果您愿意使用 gem,请考虑使用 deep_enumerable,这是我专门为此目的(以及其他目的)编写的 gem。
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
那样经过充分测试。
您可以使用 Marshal::dump 和 Marshal::load:
轻松创建自己的深度 dup 方法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}}
我将这些添加到数组和哈希中:
#数组
def deep_dup
result = []
self.each do |v|
if v.respond_to?(:deep_dup)
result << v.deep_dup
elsif v.respond_to?(:dup)
result << v.dup
else
result << v
end
end
result
end
#哈希
def deep_dup
result = {}
self.each do |k,v|
if v.respond_to?(:deep_dup)
result[k] = v.deep_dup
elsif v.respond_to?(:dup)
result[k] = v.dup
else
result[k] = v
end
end
result
end
Not
.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}