TL;DR: hash = Hash.new { |h, k| h[k] = 0 }
I’ve often needed to count or sum over a set of data. Daily sales, weekly user sign ups, and in my most recent project, monthly work units per employee. Here’s an example of summing number of orders per day:
hash = {}
orders.each do |o|
hash[o.date] += 1
end
NoMethodError: undefined method `+' for nil:NilClass
This sucks because it’s such a frequently needed action. I don’t want to write in extraneous code to set the expected key values to 0. And I finally found a solution.
hash = Hash.new { |h, k| h[k] = 0 }
orders.each do |o|
hash[o.date] += 1
end
{"2015-5-14"=>10, "2015-5-15"=>2, "2015-5-16"=>7}
This is called autovivification, which apparently comes from Perl. And it’s awesome. Any key’s value can have a default value set. Here’s another example that comes up a lot for me:
hash = {}
orders.each do |o|
hash[o.date][:state] = o.state
end
NoMethodError: undefined method `[]' for nil:NilClass
Similarly, we can set the default value for keys to another hash, which lets us assign values for nested keys immediately.
hash = Hash.new { |h, k| h[k] = {} }
Advanced Ruby Hash Techniques
Here’s an awesome resource I found from Hacker News. It covers autovivification but has some other cool tricks too: blog.honeybadger.io/advanced-ruby-hash-techniques