How to break the outer loop in Ruby?

Perl has the ability to break the outer loop as follows:

AAA: for my $stuff (@otherstuff) { for my $foo (@bar) { last AAA if (somethingbad()); } } 

(syntax may be incorrect) that uses a loop label to break the outer loop from the inner loop. Is there something similar in Ruby?

+49
ruby loops cycle
Aug 29 '09 at 18:55
source share
8 answers

What you want is a non-local control flow, which Ruby has several options:

  • Continuation
  • Exceptions and
  • throw / catch

Continuation

Pros:

  • Continuation is a standard non-local flow control mechanism. In fact, you can build any non-local control flow (subprograms, procedures, functions, methods, coroutines, state machines, generators, conditions, exceptions): they are largely a closer GOTO counterpart.

Minuses:

  • Continuations are not a mandatory part of the Ruby language specification, which means that some implementations (XRuby, JRuby, Ruby.NET, IronRuby) do not implement them. Therefore, you cannot rely on them.

Exceptions

Pros:

  • There is paper that mathematically proves that Exceptions can be more powerful than Continuations. IOW: they can do whatever the sequels can do, and much more, so you can use them as a replacement for the continuation.
  • Exceptions are available everywhere.

Minuses:

  • They are called “exceptions,” which make people think that they are “only for exceptional circumstances." This means three things: someone reading your code may not understand it, the implementation may not be optimized for it (and, yes, exceptions are pretty slow in almost any Ruby implementation), and, worst of all, you'll be sick for all these people constantly, thoughtlessly muttering "an exception only for exceptional circumstances", as soon as they look into your code. (Of course, they will not even try to understand what you are doing.)

throw / catch

This is (roughly) what it would look like:

 catch :aaa do stuff.each do |otherstuff| foo.each do |bar| throw :aaa if somethingbad end end end 

Pros:

  • Same as exceptions.
  • In Ruby 1.9, using exceptions for the control flow is actually part of the language specification! Loops, counters, iterators, etc. Use a StopIteration exception to complete.

Minuses:

  • The Ruby community hates them even more than using exceptions for control flow.
+34
Aug 29 '09 at 21:00
source share

Consider throw / catch . Usually the outer loop in the code below will be executed five times, but with a throw you can change it to whatever you want, breaking it in the process. Consider this completely correct ruby ​​code:

 catch (:done) do 5.times { |i| 5.times { |j| puts "#{i} #{j}" throw :done if i + j > 5 } } end 
+104
Aug 29 '09 at 19:02
source share

No no.

Your options:

  • put the loop in the method and use return to exit the outer loop
  • set or return a flag from the inner loop, and then check this flag in the outer loop and exit it when the flag is set (which is cumbersome)
  • use throw / catch to exit the loop
+27
Aug 29 '09 at 19:00
source share
 while c1 while c2 do_break=true end next if do_break end 

or "break if do_break" depending on what you want

+3
Sep 29 '12 at 10:21
source share

Perhaps this is what you want? (not verified)

 stuff.find do |otherstuff| foo.find do somethingbad() && AAA end end 

The find method saves the loop until the block returns a nonzero value or hits the end of the list.

+2
Aug 30 '09 at 16:21
source share

I know I will regret it this morning, but just using a while loop could do the trick.

 x=0 until x==10 x+=1 y=0 until y==10 y+=1 if y==5 && x==3 x,y=10,10 end end break if x==10 puts x end 

if y==5 && x==3 is just an example of a true expression.

0
Aug 29 '09 at 19:32
source share

Wrapping an internal method around loops can do the trick. Example:

 test = [1,2,3] test.each do |num| def internalHelper for i in 0..3 for j in 0..3 puts "this should happen only 3 times" if true return end end end end internalHelper end 

Here you can perform a check inside any of the for loops and return from the internal method after the condition is met.

0
Apr 01 '14 at 9:07
source share

You might consider adding a flag that is set in the inner loop to control the outer loop.

'next' outer loop

 for i in (1 .. 5) next_outer_loop = false for j in (1 .. 5) if j > i next_outer_loop = true if j % 2 == 0 break end puts "i: #{i}, j: #{j}" end print "i: #{i} " if next_outer_loop puts "with 'next'" next end puts "withOUT 'next'" end 

'break' outer loop

 for i in (1 .. 5) break_outer_loop = false for j in (1 .. 5) if j > i break_outer_loop = true if i > 3 break end puts "i: #{i}, j: #{j}" end break if break_outer_loop puts "i: #{i}" end 
0
Dec 21 '16 at 3:21
source share



All Articles