Rubyで多重ループを抜ける方法
Rubyの大域脱出に関するメモ。
ネストが深いループから何かの条件で一気に抜けたい場合、Rubyではcatch-throwを使うのが適切なようです。
書き方
以下が大域脱出のサンプル。如何にもサンプルの為のサンプルという感じですが、ネストしたループから抜けているのがお分かりいただけるかと。
catch(:break_loop) do (1..5).each do |x| (1..5).each do |y| puts "x=%d, y=%d" % [x,y] throw :break_loop if x * y > 10 end end end
実行結果
x=1, y=1 x=1, y=2 x=1, y=3 x=1, y=4 x=1, y=5 x=2, y=1 x=2, y=2 x=2, y=3 x=2, y=4 x=2, y=5 x=3, y=1 x=3, y=2 x=3, y=3 x=3, y=4
JavaやC++に慣れた人だと、catch節には例外処理を書くものだというイメージがあったりするのですが、Rubyの場合はその辺は切り離して考えたほうが良さそうです。
オブジェクトを返すこともできます
catch内部に定義した変数を返却する事も可能。こういう書き方を覚えておくと何かの時に役に立つのかもしれません。
(a,b,c) = catch(:break_loop) do (1..20).each do |x| (1..20).each do |y| (1..20).each do |z| throw(:break_loop, [x,y,z]) if x * y * z > 1000 end end end end puts "a=%d, b=%d, c=%d" % [a,b,c]#=>a=3, b=17, c=20
雑感
RubyはGOTO文がありませんので、上の例以外に一気にネストを抜ける為には例外をraiseするか、メソッドに分割してreturnする方法ぐらいしかありませんね。