1

The MATLAB documentation describes the break keyword thus:

  • break terminates the execution of a for or while loop. Statements in the loop after the break statement do not execute.
  • In nested loops, break exits only from the loop in which it occurs. Control passes to the statement that follows the end of that loop.

(my emphasis)

What if you want to exit from multiple nested loops? Other languages, such as Java, offer labelled breaks, which allow you to specify where the flow of control is to be transferred, but MATLAB lacks such a mechanism.

Consider the following example:

% assume A to be a 2D array

% nested 'for' loops
for j = 1 : n
  for i = 1 : m
    if f(A(i, j)) % where f is a predicate
      break; % if want to break from both loops, not just the inner one
    else
      % do something interesting with A
    end
  end
  % <--- the break transfers control to here...
end
% <--- ... but I want to transfer control to here

What is an idiomatic way (in MATLAB) of exiting from both loops?

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • 2
    Possible duplicate of [how to exit from two nested for loop in matlab](http://stackoverflow.com/questions/20302746/how-to-exit-from-two-nested-for-loop-in-matlab) – michaelsnowden Oct 08 '15 at 06:44
  • I would just extract a function and return from it – michaelsnowden Oct 08 '15 at 06:45
  • You need to use other mechanism to exit all nested loops. E.g. add more if's or pass the whole loop-strucutre to a function and then use `return` instead of `break` – rst Oct 08 '15 at 06:52
  • Why the java tag at all? – fge Oct 08 '15 at 06:52
  • @fge I refer to Java as an example of language that has labelled breaks. – jub0bs Oct 08 '15 at 06:55
  • if `n` and `m` aren't too large (i.e. no massive performance concerns) then lose the `break` entirely and just have `if A(i, j) <= 0.8, temp = temp + A(i, j)`. Checking the value of a matrix is very cheap. – Dan Oct 08 '15 at 06:55
  • @Dan Yes, I could do without a `break` in my example, but it's just an example. – jub0bs Oct 08 '15 at 06:57
  • 1
    An "idiomatic" answer will depend on the specifics of the case. Your current example, for instance, should not be a nested loop at all but would perform better using linear indexing and then a single `break` would be all you needed. – Dan Oct 08 '15 at 06:58
  • @Dan I think we're getting in the weeds, here. I'll make my example more general, not more specific. – jub0bs Oct 08 '15 at 07:00
  • 1
    Well, then your answer is "there is no way". What you are looking for might be possible in Java, but honestly, it sounds a lot like a goto in disguise. I fail to see how that feature "needs to exist" in every programming language. In Matlab you would avoid needing that feature in some other way. Usually that would be vectorizing your code. Since vectorizing your example is easily possible, that sounds like a plan. – michael_0815 Oct 08 '15 at 07:10
  • @michael_0815 I'm aware that vectorization should be pursued, whenever possible, but it is not always possible. There are ways, as shown in the answers that michaelsnowden links to, but do they scale with the level of nesting? I'm not sure. – jub0bs Oct 08 '15 at 07:12

3 Answers3

3

I would say for your original specific example, rather use linear indexing and a single loop:

%// sample-data generation
m = 4;
n = 5;
A = rand(m, n);
temp = 0;

for k = 1:numel(A)
    if A(k) > 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing
      break; 
    else
      temp = temp + A(k);
    end
end

Or the practically identical (but with less branching):

for k = 1:numel(A)
    if A(k) <= 0.8 %// note that if you had switched your inner and outer loops you would have had to transpose A first as Matlab uses column-major indexing
      temp = temp + A(k);
    end
end

I would think that this answer will vary from case to case and there is no general one size fits all idiomatically correct solution but I would approach it in the following way depending on your problem (note these all assumes that a vectorized solution is not practical as that is the obvious first choice)

  1. Reduce the dimensions of the nesting and use either no breaks or just one single break (i.e. as shown above).
  2. Don't use break at all because unless the calculation of your predicate is expensive and your loop has very many iterations, those extra iterations at the end should be practically free.
  3. Failing that set a flag and break at each level.
  4. Or finally wrap your loop into a function and call return instead of break.
Community
  • 1
  • 1
Dan
  • 45,079
  • 17
  • 88
  • 157
  • Thanks, but don't get fixated on my example (which I've since generalised). I'm just looking for a general way of exiting from multiple nested loops, that would scale well with the level of nesting. – jub0bs Oct 08 '15 at 07:04
  • @Jubobs there is no single correct way. I have added 4 methods now to my answer in order of preferance. – Dan Oct 08 '15 at 07:12
1

As far as I know there are no such functionality built in. However, in most cases matlab does not need nested loops due to its support for vectorization. In those cases where vectorization does not work, the loops are mostly long and complicated and thus multiple breaks would not hinder readability significantly. As noted in a comment, you would not really need a nested loop here. Vectorization would do the trick,

m = 5;
n=4;
x = rand(m,n);
tmp = find(x>0.8, 1, 'first');
if (isempty(tmp))
   tmp = m*n+1;
end
tmp = tmp-1;
tot = sum(x(1:tmp));

There might of course be people claiming that for loops are not necessarily slow anymore, but the fact remains that Matlab is column heavy and using more than one loop will in most cases include looping over non optimal dimensions. Vectorized solutions does not require that since they can use smart methods avoiding such loops (which of course does not hold if the input is a row vector, so avoiding this is also good).

patrik
  • 4,506
  • 6
  • 24
  • 48
0

The best idiomatic way to use Python (or poison of your choice) and forget all this but that's another story. Also I don't agree with the vectorization claims of the other answers anymore. Recent matlab versions handle for loops pretty quickly. You might be surprised.

My personal preference goes to raising an exception deliberately and cradling it within a try and catch block.

% assume A to be a 2D array
A = rand(10) - 0.5;
A(3,2) = 0;

wreaker = MException('Loop:breaker','Breaking the law');

try
    for j = 1 : size(A,1)
        % forloop number 1
        for i = 1 : size(A,2)
            % forloop number 2
            for k = 1:10
                % forloop number 3
                if k == 5 && j == 3 && i == 6
                    mycurrentval = 5;
                    throw(wreaker)
                end
            end
        end
    end
catch
    return % I don't remember the do nothing keyword for matlab apparently
end

You can change the location of your try catch indentation to fall back to the loop of your choice. Also by slaying kittens, you can write your own exceptions such that they label the exception depending on the nest count and then you can listen for them. There is no end to ugliness though still prettier than having counters or custom variables with if clauses in my opinion.

Note that, this is exactly why matlab drives many people crazy. It silently throws exceptions in a pretty similar way and you get a nonsensical error for the last randomly chosen function while passing by, such as size mismatch in some differential equation solver so on. I actually learned all this stuff after reading a lot matlab toolbox source codes.

percusse
  • 3,006
  • 1
  • 14
  • 28