Ruby Dup / клон рекурсивно - PullRequest
       48

Ruby Dup / клон рекурсивно

23 голосов
/ 03 января 2012

У меня есть хеш, как:

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 рекурсивно. Как мне этого добиться?

Ответы [ 5 ]

39 голосов
/ 03 января 2012

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

d = Marshal.load( Marshal.dump(h) )
2 голосов
/ 23 ноября 2015

Если вы в Rails: Hash.deep_dup

2 голосов
/ 15 мая 2014

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

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

h1 = h.deep_dup
1 голос
/ 10 октября 2013

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

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

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

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

Конечно, он не такой полный, так как он не будет работать, если у вас есть хеш, например, значение поля «имя_проекта», но для простого двухуровневого хеша он работает отлично / быстрее. 1008 *

0 голосов
/ 31 января 2018

Другой альтернативой является использование гема full_dup (полное раскрытие: я являюсь автором этого драгоценного камня), который обрабатывает массивы, хэши, структуры и распространяется на пользовательские классы.

Для использования:

require 'full_dup'
# Other code omitted ...
d = h.full_dup

Также обратите внимание, что full_dup обрабатывает сложные отношения данных, в том числе с циклами или рекурсией.

...