Ruby's Hash#new method accepts an optional parameter which is
returned when you try to access a key that does not exist in the hash (the default is nil). For example:
h = Hash.new('bar') #=> {}
puts h[:foo] #=> 'bar'h = Hash.new('bar') #=> {}
puts h[:foo] #=> 'bar'While the first example may not very useful, Hash#new also accepts a
block that will be called with the hash object and the key whenever you try to access
a key that does not exist in the hash, for example:
upcase = Hash.new { |hash, k| "#{k}".upcase } #=> {}
upcase['foo'] #=> "FOO"upcase = Hash.new { |hash, k| "#{k}".upcase } #=> {}
upcase['foo'] #=> "FOO"You can also modify the hash within the callback. Here's a more useful example where we create a memoized version of the fibonacci sequence:
fibonacci = Hash.new do |hash, k|
case k
when 0
hash[k] = 0
when 1, 2
hash[k] = 1
else
hash[k] = hash[k-1] + hash[k-2]
end
endfibonacci = Hash.new do |hash, k|
case k
when 0
hash[k] = 0
when 1, 2
hash[k] = 1
else
hash[k] = hash[k-1] + hash[k-2]
end
endUsing this hash, whenever we compute the nth fibonacci number all the n - 1 fibonacci numbers will be cached in the hash, significantly reducing the number of recursive calls needed to compute the next fibonacci number.
puts fibonacci[5] #=> 5
puts fibonacci #{2=>1, 1=>1, 3=>2, 4=>3, 5=>5}puts fibonacci[5] #=> 5
puts fibonacci #{2=>1, 1=>1, 3=>2, 4=>3, 5=>5}