Подтвердить что ты не робот

Ruby dup/clone рекурсивно

У меня есть хэш вроде:

h = {'name' => 'sayuj', 
     'age' => 22, 
     'project' => {'project_name' => 'abc', 
                   'duration' => 'prq'}}

Мне нужен дубликат этого хэша, это изменение не должно влиять на исходный хэш.

Когда я пытаюсь,

d = h.dup # or d = h.clone
d['name'] = 'sayuj1'
d['project']['duration'] = 'xyz'

p d #=> {"name"=>"sayuj1", "project"=>{"duration"=>"xyz", "project_name"=>"abc"}, "age"=>22}
p h #=> {"name"=>"sayuj", "project"=>{"duration"=>"xyz", "project_name"=>"abc"}, "age"=>22}

Здесь вы можете увидеть, что project['duration'] изменен в исходном хэше, потому что project - еще один хеш-объект.

Я хочу, чтобы хэш был duped или cloned рекурсивно. Как я могу достичь этого?

4b9b3361

Ответ 1

Вот как вы делаете глубокие копии в Ruby

d = Marshal.load( Marshal.dump(h) )

Ответ 2

Если пара Marchal #dump/load не работает, для существует метод Hash #deep_dup, поэтому вы можете:

h = {'name' => 'sayuj', 
 'age' => 22, 
 'project' => {'project_name' => 'abc', 
               'duration' => 'prq'}}

h1 = h.deep_dup

Ответ 3

Если вы находитесь в Rails: Hash.deep_dup

Ответ 4

Это ответ на достаточно старый вопрос, но я столкнулся с этим, когда я реализовал что-то похожее, подумал, что я буду использовать более эффективный метод.

Для простого, двухуровневого глубокого хаша, как и выше, вы также можете сделать что-то вроде этого:

d = h.inject({}) {|copy, (key, value)| 
    copy[key] = value.dup rescue value; copy
}

Я проверил тест на хэш хэшей с 4k элементами, каждый из нескольких сотен байт, и он был примерно на 50% быстрее, чем Marshal.dump/load

Конечно, это не так полно, поскольку это не сработает, если у вас есть хеш, например, значение поля project_name, но для простого хэша уровня 2 он работает отлично/быстрее.