Is there a solution to bypass 'can't add a new key into hash during iteration (RuntimeError)'?

Cristian M picture Cristian M · Aug 8, 2014 · Viewed 19.1k times · Source

I have a big problem with the expected RuntimeError: "can't add a new key into hash during iteration"

In my case a I have a YAML file: test.yaml - in which I have some keys already added.

test.yaml
key1:
key2:
key3:

I am getting the contents of the file in a variable:

file_hash = YAML.load_file("testm.yaml")

Then I need to loop through this hash and add other keys to them:

file_hash.each do |key|
   file_hash[key] = 'key_1'
   file_hash[key] = 'key_2'
end
File.open('test.yaml', 'w') { |f| YAML.dump(file_hash, f) }

The main issue is that I am unable to write into a hash while in a loop. I don't understand why this is expected, when you have the power to control the loop block. Is there another way in which I can accomplish what I showed above?

Note: I am using RUBY 1.9.3 p547

Answer

catpnosis picture catpnosis · Dec 25, 2014

Ruby since 1.9 is using lazy iteration, thus they forbid to add new keys to the hash you iterating over. As a solution you can easily duplicate hash or convert it to array before doing each.

irb(main):001:0> a={1=>1}; a.each {|k,v| a[2] = 2}
RuntimeError: can't add a new key into hash during iteration

irb(main):002:0> a={1=>1}; a.clone.each {|k,v| a[2] = 2}; a
=> {1=>1, 2=>2}

irb(main):003:0> a={1=>1}; a.to_a.each {|k,v| a[2] = 2}; a
=> {1=>1, 2=>2}