1

MATLAB 文档是这样描述break关键字的:

  • break终止 for 或 while 循环的执行。break 语句之后的循环中的语句不执行。
  • 在嵌套循环中,break 仅从它发生的循环中退出。控制传递到该循环结束之后的语句。

(我的重点)

如果你想退出多个嵌套循环怎么办?其他语言(例如 Java)提供标记的中断,允许您指定控制流的传输位置,但 MATLAB 缺少这种机制。

考虑以下示例:

% 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

从两个循环中退出的惯用方式(在 MATLAB 中)是什么?

4

3 回答 3

2

我会说你原来的 具体例子,而不是使用线性索引和单个循环:

%// 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

或几乎相同(但分支较少):

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

我认为这个答案会因情况而异,并且没有通用的一种尺寸适合所有惯用正确的解决方案,但我会根据您的问题以下列方式处理它(请注意,这些都假设矢量化解决方案不实用,因为这是明显的第一选择)

  1. 减少嵌套的尺寸并使用 nobreak或仅使用一个break(即如上所示)。
  2. 根本不要使用 break ,因为除非您的谓词计算成本很高并且您的循环有很多迭代,否则最后那些额外的迭代实际上应该是免费的。
  3. 未能设置标志并在每个级别中断
  4. 或者最后将你的循环包装成一个函数并调用return而不是break.
于 2015-10-08T07:02:47.813 回答
1

据我所知,没有内置这样的功能。但是,在大多数情况下,matlab 不需要嵌套循环,因为它支持矢量化。在向量化不起作用的情况下,循环大多是长而复杂的,因此多次中断不会显着妨碍可读性。如评论中所述,您实际上并不需要嵌套循环。矢量化可以解决问题,

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));

当然可能有人声称 for 循环不再一定很慢,但事实仍然是 Matlab 的列很重,并且在大多数情况下使用多个循环将包括在非最佳维度上循环。矢量化解决方案不需要这样做,因为它们可以使用避免此类循环的智能方法(如果输入是行向量,这当然不成立,因此避免这种情况也很好)。

于 2015-10-08T07:13:30.007 回答
0

使用 Python(或您选择的毒药)的最佳惯用方式并忘记这一切,但那是另一回事了。此外,我不再同意其他答案的矢量化声明。最近的 matlab 版本可以很快地处理 for 循环。你可能会感到惊讶。

我个人的偏好是故意引发异常并将其包含在 try 和 catch 块中。

% 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

您可以更改 try catch 缩进的位置以退回到您选择的循环。此外,通过杀死小猫,您可以编写自己的异常,以便它们根据巢数标记异常,然后您可以监听它们。在我看来,尽管仍然比使用带有 if 子句的计数器或自定义变量更漂亮,但丑陋无止境。

请注意,这正是 matlab 让许多人发疯的原因。它以非常相似的方式默默地抛出异常,并且您在经过时会为最后一个随机选择的函数得到一个无意义的错误,例如某些微分方程求解器中的大小不匹配等等。在阅读了很多 matlab 工具箱源代码后,我实际上学到了所有这些东西。

于 2015-10-08T09:30:54.890 回答