[Ruby] 再帰的group_by

やりたいこと

こういうデータ↓を

[
  { prefecture: '埼玉県', city: '深谷市',        town: '北根',   address: '3-5' },
  { prefecture: '埼玉県', city: '深谷市',        town: '北根',   address: '3-7-19' },
  { prefecture: '埼玉県', city: '深谷市',        town: '堀米',   address: '1-11-14' },
  { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新中里', address: '1-2-17' },
  { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新都心', address: '1-6-13' },
  { prefecture: '東京都', city: '品川区',        town: '西中延', address: '3-5' },
]

こう↓したい

{
  "埼玉県"=> {
    "深谷市"=> {
      "北根"=>["3-5", "3-7-19"],
      "堀米"=>["1-11-14"]
    },
    "さいたま市中央区"=> {
      "新中里"=>["1-2-17"],
      "新都心"=>["1-6-13"]
    }
  },
  "東京都"=> {
    "品川区"=> {
      "西中延"=>["3-5"]
    }
  }
}

再帰的group_by

参考:

module Enumerable
  def recursive_group_by(*props, &block)
    groups = group_by{ |e| e[props.first] }
    next_props = props.drop(1)

    if next_props.empty?
      block_given? ? block.call(groups) : groups
    else
      groups.transform_values do |e|
        e.recursive_group_by(*next_props, &block)
      end
    end
  end
end

data = [
  { prefecture: '埼玉県', city: '深谷市',           town: '北根',   address: '3-5' },
  { prefecture: '埼玉県', city: '深谷市',           town: '北根',   address: '3-7-19' },
  { prefecture: '埼玉県', city: '深谷市',           town: '堀米',   address: '1-11-14' },
  { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新中里', address: '1-2-17' },
  { prefecture: '埼玉県', city: 'さいたま市中央区', town: '新都心', address: '1-6-13' },
  { prefecture: '東京都', city: '品川区',           town: '西中延', address: '3-5' },
]

new_data = data.recursive_group_by(:prefecture, :city, :town) do |groups|
  groups.transform_values do |v|
    v.map { |x| x[:address] }
  end
end

pp data
puts '--'
pp new_data

結果

[{:prefecture=>"埼玉県", :city=>"深谷市", :town=>"北根", :address=>"3-5"},
 {:prefecture=>"埼玉県", :city=>"深谷市", :town=>"北根", :address=>"3-7-19"},
 {:prefecture=>"埼玉県", :city=>"深谷市", :town=>"堀米", :address=>"1-11-14"},
 {:prefecture=>"埼玉県", :city=>"さいたま市中央区", :town=>"新中里", :address=>"1-2-17"},
 {:prefecture=>"埼玉県", :city=>"さいたま市中央区", :town=>"新都心", :address=>"1-6-13"},
 {:prefecture=>"東京都", :city=>"品川区", :town=>"西中延", :address=>"3-5"}]
--
{"埼玉県"=>
  {"深谷市"=>{"北根"=>["3-5", "3-7-19"], "堀米"=>["1-11-14"]},
   "さいたま市中央区"=>{"新中里"=>["1-2-17"], "新都心"=>["1-6-13"]}},
 "東京都"=>{"品川区"=>{"西中延"=>["3-5"]}}}