ruby の配列のeach_with_indexのお話、とcatch throwのお話
最近rubyの「プロを目指す人のためのruby入門 伊藤淳一」という書籍を読んでいるので、 へぇこんな感じだったんだ、こんなのあるんだというものを軽く書こうと思います。今日読んだのは第4章の「配列や繰り返し処理を理解する」の部分。
そこでへぇとなった部分は2点。
・with_indexメソッドを使った添え字付き繰り返し処理
・throwとcatchを使った大域脱出
のお話です。
まず1点目
with_indexメソッドを使った添え字付き繰り返し処理
よくコードを書く際に添え字を用いた繰り返し処理の時にeach_with_indexを使うのですが、ここではeachの代わりにしか使えません。(って書いてあり、確かに、と思いました。笑) でもwith_indexメソッドを用いたらmapとかdelete_if とかにも使えるよって話です。
members = ['太郎', '二郎', '三郎'] members.map.with_index {|member, i| "#{i}: #{member}"} => ["0: 太郎", "1: 二郎", "2: 三郎"]
みたいになるよってお話です。 また
members = ['太郎', '二郎', '三郎'] member.delete_if.with_index{|member, i| member.include?('郎') && i.odd?} => ["太郎", "三郎"]
となってしまうというお話です。 ではなぜ使えるのかという話ですが。 with_indexメソッドはEnumerateオブジェクトのインスタンスメソッドです。 そしてmemberにmapやdelete_ifのメソッドにブロックを渡さない状態の返り値のEnumerateオブジェクトとなります。 したがってこのようにwith_indexが使用できるって話ですね。
throwとcatchを使った大域脱出
もう一つへぇと感じた、というか知らなかったお話です。繰り返し処理を抜け出す際や、次の要素の繰り返しに回したい時に使うのがbreakやnextですが(それしか知りませんでした)、実はその繰り返しのブロックしか抜け出せないらしいです。
2重繰り返し(重ね合わさった繰り返しなど)は1階層分しか抜け出さないようです。それらの上の層にある繰り返し処理とかも全部抜け出すのが、catchとthrowになります。(多分そいう認識で合ってます。) 例をみてみましょう まずbreak を使う場合
sum = 0 # ループ1 [*1..8].each do |n_1| #ループ2 [*1..10].each do |n_2| sum = n_1*n_2 break if n_2 == 5 end # 一回分ループ終了したら結果を出力する p sum end =>15 45 90 150 225 315 420 540
この場合はbreakはループ2のみを抜け出すのでループ1内の最後に記述されているp sumは実行され8回分の結果が表示されます。
ではcatch throwを使った場合
sum = 0 catch :doen do # ループ1 [*1..8].each do |n_1| #ループ2 [*1..10].each do |n_2| sum = n_1*n_2 throw :doen if n_2 == 5 end # 一回分ループ終了したら結果を出力する p sum end end =>
この場合結果は何も現れません。なぜかというと一回目のループ2でthrowが実行され(ループ2の5週目で)1回目のループも抜け出してしまうからです。
というようなお話でした。 ある程度railsを使って実装できるようになったものの知らないメソッドとか色々あるもんだなぁって感じました。