【问题标题】:Create hash-of-hashes using structure of the default hash使用默认哈希的结构创建哈希哈希
【发布时间】:2015-10-06 12:49:00
【问题描述】:

我有以下代码:

default = {:id => 0, :detail =>{:name=>"Default", :id => ""}}
employees = {}

nr = (0..3).to_a 
nr.each do |n|
    employee = default
    employee[:id] = n
    employee[:detail][:name] = "Default #{n}"
    employee[:detail][:id] = "KEY-#{n}"
    employees[n] = employee
end
puts employees

我希望 :detail 哈希中的键 :id 的值是 KEY-0KEY-1KEY-2

【问题讨论】:

  • 请编辑说明您的问题。

标签: ruby hash hash-of-hashes


【解决方案1】:

你只需要改变:

default = { :id=>0, :detail=>{ :name=>"Default", :id=>"" } }

def default
  {}.merge(:id=>0, :detail=>({}.merge(:name=>"Default", :id=>"")))
end

但是,嘿,虽然我们这样做了,但我们不妨将其余部分 Ruby 化:

employees = (0..3).map do |n|
    employee = default
    employee[:id] = n
    employee[:detail][:name] = "Default #{n}"
    employee[:detail][:id] = "KEY-#{n}"
    employee
end
  #=> [{:id=>0, :detail=>{:name=>"Default 0", :id=>"KEY-0"}},
  #    {:id=>1, :detail=>{:name=>"Default 1", :id=>"KEY-1"}},
  #    {:id=>2, :detail=>{:name=>"Default 2", :id=>"KEY-2"}},
  #    {:id=>3, :detail=>{:name=>"Default 3", :id=>"KEY-3"}}] 

让我们确认我们正在制作 default 的深层副本:

employees[0][:detail][:id] = "cat"
employees
  #=> [{:id=>0, :detail=>{:name=>"Default 0", :id=>"cat"}},
  #    {:id=>1, :detail=>{:name=>"Default 1", :id=>"KEY-1"}},
  #    {:id=>2, :detail=>{:name=>"Default 2", :id=>"KEY-2"}},
  #    {:id=>3, :detail=>{:name=>"Default 3", :id=>"KEY-3"}}] 

你更常看到这样写:

employees = (0..3).map do |n|
  default.merge(:id=>n, :detail=>{:name=>"Default #{n}", :id=>"KEY-#{n}"})
end
  #=> [{:id=>0, :detail=>{:name=>"Default 0", :id=>"cat"}},
  #    {:id=>1, :detail=>{:name=>"Default 1", :id=>"KEY-1"}},
  #    {:id=>2, :detail=>{:name=>"Default 2", :id=>"KEY-2"}},
  #    {:id=>3, :detail=>{:name=>"Default 3", :id=>"KEY-3"}}] 

根据其他答案的建议,您可以这样做:

class Object
  def deep_copy
    Marshal.load(Marshal.dump(self))
  end
end

那么你可以写:

default = { :id=>0, :detail=>{ :name=>"Default", :id=>"" } }
employees = (0..3).map do |n|
  default.deep_copy.merge(:id=>n, :detail=>{:name=>"Default #{n}",
    :id=>"KEY-#{n}"})
end
  #=> [{:id=>0, :detail=>{:name=>"Default 0", :id=>"KEY-0"}},
  #    {:id=>1, :detail=>{:name=>"Default 1", :id=>"KEY-1"}},
  #    {:id=>2, :detail=>{:name=>"Default 2", :id=>"KEY-2"}},
  #    {:id=>3, :detail=>{:name=>"Default 3", :id=>"KEY-3"}}] 

这样做的好处是,如果您更改 default,则无需进行其他更改。

【讨论】:

    【解决方案2】:

    你需要整理你的默认值才能复制

    default = {id: 0, detail: {name: "Default", id:""}}
    employees = {}
    4.times do |n|
      employees[n] = Marshal.load(Marshal.dump(default))
      employees[n][:id] = n
      employees[n][:detail][:name] = "Default #{n}"
      employees[n][:detail][:id] = "KEY-#{n}"
    end
    puts employees
    

    输出是

    {0=>{:id=>0, :detail=>{:name=>"Default 0", :id=>"KEY-0"}}, 1=>{:id=>1, :detail=>{:name=>"Default 1", :id=>"KEY-1"}}, 2=>{:id=>2, :detail=>{:name=>"Default 2", :id=>"KEY-2"}}, 3=>{:id=>3, :detail=>{:name=>"Default 3", :id=>"KEY-3"}}}
    

    您可以阅读这篇文章Cloning an array with its content

    添加

    这里有一个 reduce 版本,如果你愿意,应该会更快。

    employees = {}
    4.times { |n| employees[n]={id: n, detail: {name: "Default #{n}", id:"KEY-#{n}"}} }
    puts employees
    

    【讨论】:

      【解决方案3】:

      您在每次迭代中制作浅拷贝,即每次使用上次迭代中计算的值覆盖每个副本。您可以尝试以下方法为您的 hash-within-hash 默认模式进行深层复制:

      employee = Marshal.load(Marshal.dump(default))
      

      Demonstration

      【讨论】:

        猜你喜欢
        • 2013-12-20
        • 1970-01-01
        • 2011-04-20
        • 2011-05-27
        • 2011-09-20
        • 2012-08-17
        • 1970-01-01
        • 2011-02-27
        相关资源
        最近更新 更多