gouf
11/7/2016 - 10:30 AM

駅データ.jp (www.ekidata.jp) で配布されているデータをいい感じにHash に合成する

駅データ.jp (www.ekidata.jp) で配布されているデータをいい感じにHash に合成する

require 'csv'
require 'pp' # pretty print

module EkidataJp;end

module EkidataJp::Exception;end

class EkidataJp::Exception::NoPresentStationCsvHeader < StandardError
  def message
    'Please specify some of EkidataJp::CombineStationNameAndPref#station_csv_headers'
  end
end

# ekidata.jp からダウンロードした2ファイル(駅名一覧、都道府県)を合成する
class EkidataJp::CombineStationNameAndPref
  attr_reader :station_csv_path, :pref_csv_path

  # @param station_csv_path [string]
  # @param pref_csv_path [string]
  # @param headers [Array<Symbol>]
  def initialize(station_csv_path:, pref_csv_path:, headers: )
    @station_csv_path = station_csv_path
    @pref_csv_path = pref_csv_path
    @station_name_table = parse_station_csv(headers)
  end

  # @return [Array<Symbol>]
  # 駅名CSVのヘッダを返す
  def station_csv_headers
    CSV.table(@station_csv_path).headers
  end

  # @return [Array<Hash>]
  # 2つのCSVファイル(駅名一覧、都道府県)を合成して返す
  def combine_station_and_pref
    @station_name_table.map do |arr|
      h = arr.inject({}) { |hash, values| hash.merge(values) }
      h.merge(pref_name: find_pref_name(h[:pref_cd]))
    end
  end

  # 駅名CSV をパース 1つ以上の指定されたヘッダキーを返す
  def parse_station_csv(*header_keys)
    header_keys.flatten!
    raise EkidataJp::Exception::NoPresentStationCsvHeader if header_keys.size.zero?
    header_keys << :pref_cd unless header_keys.include?(:pref_cd)

    @station_name_table ||=
      CSV.table(@station_csv_path).map do |row|
        header_keys.map { |key| { key => row.field(key) } }
      end
    @station_name_table
  end

  # 都道府県CSV をパース 都道府県名とそれに対応するコードを返す
  def parse_pref_csv
    @pref_table =
      CSV.table(@pref_csv_path).map do |row|
        {
          pref_cd: row.field(:pref_cd),
          pref_name: row.field(:pref_name)
        }
      end
  end

  # 指定されたpref_cd と対応する都道府県名を返す
  def find_pref_name(pref_cd)
    parse_pref_csv if @pref_table.nil?

    @pref_table.find { |hash| hash[:pref_cd].eql?(pref_cd) }[:pref_name]
  end
end

pref_csv_path = '/path/to/pref.csv'
station_csv_path = '/path/to/stationyyyymmddfree.csv'

e = EkidataJp::CombineStationNameAndPref.new(station_csv_path: station_csv_path, pref_csv_path: pref_csv_path, headers: %i(station_name))

pp e.combine_station_and_pref