Ruby手習い(正規表現)

アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問) - give IT a try

上記記事のカラオケマシーン問題。

自分で書いたコード

class KaraokeMachine
    KEYS = %w(C C# D D# E F F# G G# A A# B)

    def initialize(melody)
        @melody = melody
    end
        
    def transpose(diff)
        @melody.gsub(/[A-G]#?/) {|l| KEYS[(KEYS.index(l)+diff)%12]}
    end
end

出題者による回答例

class KaraokeMachine
  SCALE = %w(C C# D D# E F F# G G# A A# B).freeze

  def initialize(melody)
    @melody = melody
  end

  def transpose(amount)
    converter = [SCALE, SCALE.rotate(amount)].transpose.to_h
    @melody.gsub(/[A-G]#?/, converter)
  end
end

「CodeIQ ベストコード発表会 ~最もエレガントにカラオケマシン問題を解いた挑戦者は誰だ!?~」を放送しました #sg_study - give IT a try

学んだこと

  • 正規表現全然知らなかったがちょっと知った。
  • 最初gsubの第一引数をRegexp.new(KEYS.join('|'))でつくろうとして、F#Fの部分がヒットしてしまう問題に直面した。FF#をヒットさせたければF#?とすぐに発想できたかった。
  • 定数がミュータブルなオブジェクトの場合、再代入は警告だすけど実行できてしまう。再代入できないようにするにはfreezeする必要あり。
  • gsubの第二引数に文字列じゃなくてハッシュ渡せる!覚えておきたい。(ヒットした文字列をもとにあれこれ操作したい場合はブロックをつかう。)
  • Array#rotate(count)配列の要素を回転させるみたいに動かせる。
  • Array#transposeで行列の転置みたいな操作ができる。
  • converter = [SCALE, SCALE.rotate(amount)].transpose.to_hカコイイ…