Search code examples
rubyhashreduceautovivification

Getting frequency of nested elements, with relationship retained


I have an array of

  • shop objects

    • which belong to city objects

      • which belong to prefecture objects

I'd like to end up with a hash listed by prefecture, then city, then frequency...

I came up with this, but it feels really un-rubylike..

city_by_prefecture = shop_list.reduce({}){ |h,e|
  if h[e.prefecture.name].nil?
    h[e.prefecture.name] = {e.city.name => 1}
  elsif h[e.prefecture.name][e.city.name].nil?
    h[e.prefecture.name][e.city.name] = 1
  else
    h[e.prefecture.name][e.city.name] += 1
  end
  h
}

There must be a DRY-er way to do this !


Solution

  • city_by_prefecture = shop_list.each_with_object({}){ |e,h|
      h[e.prefecture.name] ||= Hash.new(0)
      h[e.prefecture.name][e.city.name] += 1
    }