Logo

Programming-Idioms

  • Java
  • Ruby
  • Haskell
  • Python

Idiom #43 Break outer loop

Look for a negative value v in 2D integer matrix m. Print it and stop searching.

Control flow jumping forward after the end of the outermost loop
import static java.lang.System.out;
int i, j, M = m.length, N = m[0].length, x;
boolean b = false;
for (i = 0; i < M; ++i) {
    for (j = 0; j < N; ++j)
        if ((x = m[i][j]) < 0) {
            out.println(x);
            b = true;
            break;
        }
    if (b) break;
}
mainloop: for(int i=0;i<m.length;i++)
	for(int j=0;j<m[i].length;j++)
		if(m[i][j]<0){
			System.out.println(m[i][j]);
			break mainloop;
		}

mainloop is a label used to refer to the outer loop.
import static java.lang.System.out;
   int i, j, M = m.length, N = m[0].length, x;
a: for (i = 0; i < M; ++i)
       for (j = 0; j < N; ++j)
           if ((x = m[i][j]) < 0) {
               out.println(x);
               break a;
           }

"... The break statement terminates the labeled statement ... Control flow is transferred to the statement immediately following the labeled (terminated) statement."
negative_value = catch :negative do
  matrix.each do |row|
    row.each do |value|
      throw :negative, value if value < 0
    end
  end
end

puts negative_value
(print . head . filter (<0) . concat) m

Haskell's lazy evaluator takes care of breaking all looping when no more searching is needed beyond the first found negative
z = False
for a in m:
    for b in a:
        if z := b < 0:
            print(b)
            break
    if z: break
from itertools import chain
matrix = [[1,2,3],[4,-5,6],[7,8,9]]
try:
    print(next(i for i in chain.from_iterable(matrix) if i < 0))
except StopIteration:
    pass

We make a generator that will return negative values from a list (and use chain.from_iterable(matrix) to lazily extract the values) and only take one value from it with the next function. The generator will not continue until we call next again.

This will raise StopIteration if it doesn't find the value so we need to account for it.
def loop_breaking(m, v): 
    for i, row in enumerate(m): 
        for j, value in enumerate(row): 
            if value == v: 
                return (i, j)
    return None

print(loop_breaking(([1,2,3],[4,5,6],[7,8,9]), 6))

Rather than set break flags, it is better to refactor into a function, then use return to break from all nested loops.
class BreakOuterLoop (Exception): pass

try:
    position = None
    for row in m:
        for column in m[row]:
            if m[row][column] == v:
                position = (row, column)
                raise BreakOuterLoop
except BreakOuterLoop:
    pass

This is ugly because the pythonic way to solve this problem would be to refactor so that one doesn't have to break out of multiple loops. See PEP3136
Outer_loop:
for A in M'Range (1) loop
   Inner_Loop:
   for B in M'Range (2) loop
      if M (A, B) < 0 then
         Put_Line (M (A, B)'Image);
         exit Outer_Loop;
      end if;
   end loop Inner_Loop;
end loop Outer_Loop;

New implementation...
< >
programming-idioms.org