LoginSignup
6
1

More than 1 year has passed since last update.

【Ruby のまずいコード】ハッシュのキーのシンボル化

Last updated at Posted at 2021-12-07

お題

キーが文字列であるハッシュが与えられたとき,各キーをシンボルにするメソッドを書いてください。

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_hHash#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 というメソッドもあり,こちらもいろんな場面で使います。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1