Generating hash hashes using the default hash structure
I have the following code:
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
I expect that the value for a key :id
in :detail
a hash are KEY-0
, KEY-1
, KEY-2
.
source to share
You only need to change:
default = { :id=>0, :detail=>{ :name=>"Default", :id=>"" } }
to
def default
{}.merge(:id=>0, :detail=>({}.merge(:name=>"Default", :id=>"")))
end
but hey, while we're at it, we can Ruby-iize the rest:
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"}}]
Please confirm that we are making deep copies 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"}}]
You would see this more often:
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"}}]
As suggested by other answers, you could:
class Object
def deep_copy
Marshal.load(Marshal.dump(self))
end
end
Then you could write:
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"}}]
This has the advantage that default
no other changes are required when changing .
source to share
You will need marshall for your default to copy
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
Output signal
{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"}}}
You can read this post Cloning an Array with Its Contents
ADDED
And here you have a smaller version and should be faster if you want.
employees = {}
4.times { |n| employees[n]={id: n, detail: {name: "Default #{n}", id:"KEY-#{n}"}} }
puts employees
source to share