web-dev-qa-db-ja.com

Rubyでネストされたループから抜ける方法は?

次のRubyコード:

bank.branches do |branch|
  branch.employees.each do |employee|
    NEXT BRANCH if employee.name = "John Doe"
  end
end

NEXT BRANCHはもちろん擬似コードです。親ループから抜け出す方法はありますか、たとえばPerlで行うことができます(ループラベルを使用することによって)?

前もって感謝します。

50
crlsrns

Catchおよびthrowはあなたが探しているものかもしれません:

bank.branches do |branch|
  catch :missingyear do  #:missingyear acts as a label
    branch.employees.each do |employee|
      (2000..2011).each do |year|
        throw :missingyear unless something  #break out of two loops
      end
    end
  end #You end up here if :missingyear is thrown
end
88
steenslag

同意なしに包含ブロックから抜け出す組み込みの方法はありません。次のようなことをするだけです。

bank.branches do |branch|
  break unless branch.employees.each do |employee|
    break if employee.name == "John Doe"
  end
end
16
Chuck
while c1
 while c2
    # execute code
    do_break = true if need_to_break_out_of_parent_loop
 end
 break if do_break
end
6
Anno2001

私の衝動は、returnの代わりにbreakを使用して、ネストされたブロックをメソッドに移動することです。

def find_branch_and_employee_by_name(bank,emp_name)
  bank.branches.each do |branch|
    branch.employees.each do |employee|
      return([branch,employee]) if employee.name == emp_name
    end
  end
  nil   # employee wasn't found
end
4
Stovey

他の投稿では、「スイッチ」変数の作成に似たアイデアを参照しています。仕組みの明確な例については、以下を参照してください。 2番目のループは、従業員配列の最後に到達するまで実行されますが、スイッチが切り替えられた後はコードを実行しないことに注意してください。これは、従業員の配列が大きい場合、不必要に時間がかかる可能性があるため、これを行う最適な方法ではありません。

def workforce
  bank.branches do |branch|
    switch = 0
    branch.employees.each do |employee|
      if switch == 1
       next
      end  
      if employee.name = "John Doe"
       switch = 1
      end
   end
 end

スイッチが反転されると、内側の配列はアクティブではなくなり、スイッチがリセットされると、親ループは次のブランチに移動します。明らかに、より複雑な場合にはより多くのスイッチを使用できます。

0
MusicIsFreedom

編集:目的の効果は、内側のループ内でbreakを呼び出すことにより、はるかに簡単に達成できます(そのループのみを終了します)。

bank.branches do |branch|
  branch.employees.each do |employee|
    break if employee.name = "John Doe"
  end
end

これは、@ steenslagがRuby begin-rescue-endブロックで書かれたものです:

letters = [%w(a b c),%w(d e f),%w(g h i)]
# => [["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]

letters.each do |trine|
  begin
    trine.each do |letter|
      raise "Breaking out of inner cycle." if letter == "e"
      puts letter
    end
  rescue
    next
  end
end
# => abcdghi

あなたの例は次のとおりです。

bank.branches do |branch|
  branch.employees.each do |employee|
    begin
      raise "Breaking out of inner cycle." if employee.name = "John Doe"
    rescue
      next
    end      
  end
end
0
Epigene