お題
キーが文字列であるハッシュが与えられたとき,各キーをシンボルにするメソッドを書いてください。
Ruby on Rails には(より詳しく言えば Active Support には)そのためのメソッド Hash#symbolize_keys
があるのですが,これを使わず自分で実装することとします。
コード
コード 1
def hash_symbolize_keys(hash)
result = {}
hash.each do |key, value|
result[key.to_sym] = value
end
result
end
コード 2
def hash_synbolize_keys(hash)
hash.map{ |key, value| [key.to_sym, value] }.to_h
end
コード 3
def hash_symbolize_keys(hash)
hash.to_h{ |key, value| [key.to_sym, value] }
end
改善
コード 1 は初心者が書きがちなコードですね。とても素直な発想で,Enumerable#to_h や Hash#to_h を知らなければ誰でもこのような書き方をするのではないでしょうか。
Enumerable#to_h を知っていれば,コード 2 のように簡潔な書き方ができます。
このメソッドは,Enumerable なオブジェクト(つまり大雑把に言えば each
メソッドを持つオブジェクト)からハッシュを作るさまざまな場面で役に立ちます。
しかし,ハッシュも Enumerable であることと,to_h
にはブロックを与える用法もある,ということに気づけば,map
で変換してから to_h
しなくても,ハッシュに直接 to_h
すればよい,と分かります。
それがコード 3。
実は Hash クラスには独自に to_h
メソッドが実装されていて,コード 3 の to_h
は Enumerable の to_h
ではなく Hash の to_h
なのですが,今の場合 Enumerable の to_h
のつもりで理解しようとしてもさしつかえありません。
しかし,もっと簡潔に書けます。
Hash には,キーを変換する専用メソッド Hash#transform_keys が用意されているからです。
これを使えば
def hash_symbolize_keys(hash)
hash.transform_keys{ |key| key.to_sym }
end
と書けます。
これはもちろん
def hash_symbolize_keys(hash)
hash.transform_keys(&:to_sym)
end
とか(Ruby 2.7 以降なら)
def hash_symbolize_keys(hash)
hash.transform_keys{ _1.to_sym }
end
とも書けます。あとの二者のほうが簡素で瞬間的に把握しやすいと私は思います。
速度面でも,transform_keys
を用いたほうがコード 3 よりも何割か速いようなので,多数回実行するような場合や競技プログラミングでは身につけておきたいところです。
なお,ハッシュの要素のキーではなく値のほうを変換する Hash#transform_values というメソッドもあり,こちらもいろんな場面で使います。