在 Ruby 中复制哈希

问题描述 投票:0回答:4

我试图通过使用另一个具有默认值的哈希来初始化 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}} 
ruby hash
4个回答
6
投票

就@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
那样经过充分测试。


3
投票

您可以使用 Marshal::dumpMarshal::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}} 

0
投票

我将这些添加到数组和哈希中:

#数组

  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

-1
投票

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}
© www.soinside.com 2019 - 2024. All rights reserved.