0

a is a hash. s is an array where I want to push the hash a iteratively. The idea is to retain the value of each iteratively pushed hash independently. Here is what I tried.

a = {:a=> 1, :b=>2}

s = []
s << a
s << a     # => [{:b=>2, :a=>1}, {:b=>2, :a=>1}]
a[:b] = 3
s          # => [{:b=>3, :a=>1}, {:b=>3, :a=>1}]

t = []
t.push(a)    # => [{:b=>3, :a=>1}]
t.push(a)    # => [{:b=>3, :a=>1}, {:b=>3, :a=>1}]
a[:b] = 4
t            # => [{:b=>4, :a=>1}, {:b=>4, :a=>1}]

The above doesn't give me the solution: Changing a changes the values in the elements inside the array which were previously pushed. After pushing a to s twice, I changed a[:b] from 2 to 3, and all the elements reflected the change. Suggestion for this please.

sawa
  • 165,429
  • 45
  • 277
  • 381
Saurajeet
  • 1,088
  • 2
  • 8
  • 10
  • 1
    Essentially dup of [How do I copy a hash in Ruby?](http://stackoverflow.com/questions/4157399/how-do-i-copy-a-hash-in-ruby) – dbenhur Oct 22 '12 at 03:30

2 Answers2

5

Use dup every time you're adding to s

s << a.dup

The dup method will create shallow copy of hash.

Update:

In case if the shallow copy doesn't satisfy the requirements, then use Marshaling

s << Marshal.load( Marshal.dump(a) )
megas
  • 21,401
  • 12
  • 79
  • 130
  • [`Object#dup`](http://ruby-doc.org/core-1.9.3/Object.html#method-i-dup) only makes a shallow copy. If `a` had an element `:c => [1,2]` and after the copy he modified `a[:c] << 3`, then the copy pushed onto his array will also see that change. – dbenhur Oct 22 '12 at 03:19
  • @dbenhur, you're right, see the update – megas Oct 22 '12 at 03:53
2

Use

s << Hash[a]

This will copy the Hash and allow you to change the original.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
  • Similarly to `#dup` this only makes a shallow copy. If `a` had an element `:c => [1,2]` and after the copy he modified `a[:c] << 3`, then the copy pushed onto his array will also see that change – dbenhur Oct 22 '12 at 03:19