2015-07-16 4 views
3

У меня есть следующий код:Создание хэш-из-хэшей, используя структуру хэш по умолчанию

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 

Я ожидаю, что значения ключа :id в :detail хэш быть KEY-0, KEY-1, KEY-2.

+0

Измените, пожалуйста, свой вопрос. –

ответ

0

Вы делаете мелкую копию на каждой итерации, то есть каждый раз, когда каждая копия переопределяется значениями, рассчитанными на последней итерации. Вы можете попробовать следующее для вас шаблон хэш-в-хэш по умолчанию, чтобы сделать глубокую копию:

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

Demonstration

0

Вам потребуется Маршалловых ваше значение по умолчанию для копирования

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

ДОБАВЛЕНО

И здесь у вас есть уменьшить версию и должен быть быстрее, если вы хотите.

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

Вам нужно только изменение:

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

к

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

но, эй, в то время как мы на это мы можем, а рубин Изе остальное:

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"}}] 

Это имеет то преимущество, at, если вы меняете default, никаких других изменений не требуется.

Смежные вопросы