へい

学んだこととか、思ったこと。プログラミングしてみたり、野球したり、筋トレしたり、hiphop聞いたり、格闘技見たりするのが好き。

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を使って実装できるようになったものの知らないメソッドとか色々あるもんだなぁって感じました。