Hash initializers:
# this
animals = Hash.new { [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {}
# is not the same as this
animals = Hash.new { |_animals, type| _animals[type] = [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]}
I saw someone post these on another question, but I don't understand why animals appears blank in the first case. If I type
animals[:dogs]
I get the appropriate array.
In the first case, the default value returned when the key does not exist is []
. The various statements then successfully add various dogs and squirrels to the returned arrays.
However, at no point is a key ever created for :dogs
or :squirrels.
In the second case, the block does store the new value back into a hash entry using the key.
One thing here that is somewhat interesting is how you keep getting a new empty array back in the first case. And the answer is: you did not pass []
as a parameter but as a block. That's executable and it is saved as a proc. Every time a key is not found, the proc runs again and generates a new []
.
You can see this in operation, note the different object id values:
irb > t = Hash.new { [] }
=> {}
irb > t[:a].object_id
=> 2149202180
irb > t[:a].object_id
=> 2149192500
The first form specifies the block that returns a default value for a key that isn't found. That means that when you invoke animals[:dogs]
, there is no :dogs
key in the hash, so your block gets invoked and animals[:dogs]
evaluates to the result of your block, i.e. []
. What happens then is that << :Scooby
appends :Scooby
to that empty list, which is then happily discarded.
The second form specifies the block that, when a key is requested and isn't found, receives as parameters the hash itself and the key that hasn't been found. It's a slightly more powerful version of the first constructor. The difference is in what your block does. In this second form, you modify the hash to associate []
with the key that hasn't been found. So now it's stored inside the hash and << :Scooby
will store :Scooby
there. Further calls for :dog
won't trigger the block, because now :dog
exists in the hash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With