I have a hash like:
h = {'name' => 'sayuj',
'age' => 22,
'project' => {'project_name' => 'abc',
'duration' => 'prq'}}
I need a dup of this hash, the change should not affect the original hash.
When I try,
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}
Here you can see the project['duration']
is changed in the original hash because project
is another hash object.
I want the hash to be duped
or cloned
recursively. How can I achieve this?
Here's how you make deep copies in Ruby
d = Marshal.load( Marshal.dump(h) )
In case the Marchal
#dump/load
pair isn't work, for rails there is a Hash
's method #deep_dup
, so you can:
h = {'name' => 'sayuj',
'age' => 22,
'project' => {'project_name' => 'abc',
'duration' => 'prq'}}
h1 = h.deep_dup
If you are in Rails: Hash.deep_dup
This is an answer to a reasonably old question, but I happened upon it while implementing something similar, thought I'd chime in for a more efficient method.
For the simple, two level deep hash like above, you can also do something like this:
d = h.inject({}) {|copy, (key, value)|
copy[key] = value.dup rescue value; copy
}
I ran a test on a hash of hashes with 4k elements, each a few hundred bytes, and it was about 50% faster than the Marshal.dump/load
Of course, it's not as complete, as it won't work if you have a hash as, e.g., the value of the 'project_name' field, but for a simple 2 level hash, it works great / faster.
Another alternative is to use the full_dup gem (full disclosure: I am the author of that gem) that handles arrays, hashes, structs, and is extendable to user defined classes.
To use:
require 'full_dup'
# Other code omitted ...
d = h.full_dup
Also note that full_dup handles complex data relationships including those with loops or recursion.