How to break from nested loops in Ruby?

RubyLoopsNested Loops

Ruby Problem Overview


assume the following ruby code:

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

NEXT BRANCH is of course pseudocode. is there a way that i can break out of a parent loop, the way one can do so in Perl, for example (by employing loop labels)?

thanks in advance.

Ruby Solutions


Solution 1 - Ruby

Catch and throw might be what you are looking for:

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

Solution 2 - Ruby

There's no built-in way to break out of containing blocks without their consent. You'll just have to do something like:

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

Solution 3 - Ruby

while c1
 while c2
    # execute code
    do_break = true if need_to_break_out_of_parent_loop
 end
 break if do_break
end

Solution 4 - Ruby

My impulse would be to move the nested blocks into a method, with a return in place of the 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

Solution 5 - Ruby

Edit: The desired effect, turns out, can be achieved much more simply by calling break inside the inner loop (will only terminate that loop):

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

Here is what @steenslag was getting at written with Ruby begin-rescue-end block:

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

So your example is:

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

Solution 6 - Ruby

Other posts have referenced an idea similar to creating a "switch" variable. See below for a clear example of how it works. Keep in mind the second loop will still be running until it reaches the end of the employee array, but will not execute any code after the switch is flipped. This is not the optimal way to do this as it can be unnecessarily time expensive if your employee array is large.

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

After the switch is flipped the inner array will no longer be active and the parent loop will move to the next branch with the switch reset. Obviously more switches can be used for more complex cases.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncrlsrnsView Question on Stackoverflow
Solution 1 - RubysteenslagView Answer on Stackoverflow
Solution 2 - RubyChuckView Answer on Stackoverflow
Solution 3 - RubyAnno2001View Answer on Stackoverflow
Solution 4 - RubyStoveyView Answer on Stackoverflow
Solution 5 - RubyEpigeneView Answer on Stackoverflow
Solution 6 - RubyMusicIsFreedomView Answer on Stackoverflow