There are several ways of making this more idiomatic:
A trivial note, but don't use Array.new
.
Use []
, it's shorter, clearer, and more idiomatic
Don't use category_hash[category] = [] unless category_hash[category]
Instead, use category_hash[category] ||= []
. In general you can use a ||= b
instead of a = b unless a
. In the case of hashes, you can skip this completely and just give the hash an appropriate default value:
category_hash = Hash.new { |hash,key| hash[key] = [] }
Don't initialize a collection to an empty state, and then iterate over another collection, appending to the new collection. Use map
/each_with_object
/inject
/etc. to turn one collection into another collection
A more idiomatic solution might look like this:
category_hash = things.each_with_object(Hash.new {|h,k| h[k] = [] }) do |thing,hash|
thing.categories.each { |cat| hash[cat] << thing }
end
A completely different approach would be to map each thing
's categories into a new hash, and then merge the resulting hashes. The problem is that you need a "deep" merge, like the one that comes with ActiveSupport:
categories_hash = things.map do |thing|
Hash[thing.categories.map { |cat| [cat,thing] }]
end.reduce(&:deep_merge)