How to break from nested loops in Ruby?
RubyLoopsNested LoopsRuby 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.