Multi-value hashes in Ruby
Any non-trivial project quickly finds itself needing data structures that are more exotic than simple arrays or maps. In my quest for multimap nirvana, I first found references where every value-put call would need to be changed to look like this:
> h = {} > (h[:key] ||= []) << "value 1" > (h[:key] ||= []) << "value 2" > puts h {:key=>["value 1", "value 2"]}
Obviously, not DRY, and painful to look at. I came across this post which talks about using the hash constructor:
> h = Hash.new{|h,k| h[k] = []} > h[:key] << "value 1" > h[:key] << "value 2" > puts h {:key=>["value 1", "value 2"]}
OK, I think I can live with that.
If you want a multi-value hash whose values are never duplicated, use Set.new
in the constructor instead of an array.
If you need arbitrary-depth hashes, though, check this out:
> h = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc) } > h[:a][:b][:c] = "123" > puts h {:a=>{:b=>{:c=>"123"}}}
The default_proc mechanics are explained very well here.