Logo

Programming-Idioms

  • Ruby
  • C++
  • Haskell
  • C#

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
using System;
foreach (int v in m)
{
    if (v < 0)
    {
        Console.WriteLine(v);
        break;
    }
}

m is int[,]

Enumeration of a multidimensional array can be handled by the compiler.
using System;
for (
        int i = 0,
        rows = m.GetLength(0),
        cols = m.GetLength(1); i < rows; i++)
{
    for (int j = 0; j < cols; j++)
    {
        if (m[i, j] < 0)
        {
            Console.WriteLine(m[i, j]);
            i = int.MaxValue - 1; // Break outer loop.
            break;
        }
    }
}

A straightforward way without using goto is to (if applicable) set the outer loop's iteration variable out of bounds and leave a comment explaining the technique.
using System;
foreach (int[] row in m)
{
    foreach (int v in row)
    {
        if (v < 0)
        {
            Console.WriteLine(v);
            goto DONE;
        }
    }
}
DONE: ;

In this case, m is int[][], an array of arrays, so foreach loops can be used.

foreach loops have no out-of-bounds condition; goto becomes the clearest alternative to extracting the loops into a method.
bool keepLooping = true;

for(int i = 0; i < m.length && keepLooping; i++)
{
	for(int j = 0; j < m[i].length && keepLooping; j++)
	{
		if(m[i][j] < 0)
		{
			Console.WriteLine(m[i][j]);
			keepLooping = false;
		}
	}
}

Trying to avoid GOTO with this implementation.
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
#include <iostream>
auto indices = findNegativeValue (m, 10, 20);
std::cout << m[indices.first][indices.second] << '\n';

std::pair<int, int> findNegativeValue (int **m, int rows, int columns) {
  for (int i = 0; i < rows; ++i) {
    for (int j = 0; j < columns; ++j) {
      if (m[i][j] < 0) return make_pair (i, j);
    }
  }
  throw "No negative value!";
}

Whenever the code is as complicated as you need to break the outer loop, it is the correct time to add a new function.

edit: The above comment is an opinion and adds nothing to presenting a solution to the stated problem. It is a narrow-minded opinion to think such a statement can apply to every conceivable situation.
(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
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