退出多个嵌套循环的惯用方式?
Idiomatic way of exiting from multiple nested loops?
MATLAB documentation 描述了 break
关键字:
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.
(我的重点)
如果要退出多个嵌套循环怎么办?其他语言,例如 Java,提供 labelled breaks,它允许您指定控制流将转移到哪里,但是 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 中)是什么?
对于您的 原始 特定 示例,我会说,而是使用线性索引和单个循环:
%// 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
我认为这个答案会因情况而异,并且没有通用的通用尺寸适合所有 惯用正确的 解决方案,但我会按照以下方式处理它,具体取决于您的问题(请注意,所有这些都假设矢量化解决方案不切实际,因为这是显而易见的首选)
- 减少嵌套的尺寸,不使用
break
或只使用一个 break
(即如上所示)。
- Don't use break at all 因为除非你的谓词的计算很昂贵并且你的循环有很多次迭代,否则最后那些额外的迭代实际上应该是免费的。
- 失败 set a flag and break at each level。
- 或者最后将循环包装到函数中并调用
return
而不是 break
。
据我所知,没有内置这样的功能。但是,在大多数情况下,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 是列繁重的,并且在大多数情况下使用多个循环将包括在非最佳维度上循环。矢量化解决方案不需要这样做,因为它们可以使用避免此类循环的智能方法(如果输入是行向量,这当然不成立,因此避免这种情况也很好)。
使用 Python(或您选择的毒药)的最佳惯用方法并忘记这一切,但这是另一回事。此外,我不再同意其他答案的矢量化声明。最近的 matlab 版本处理 for 循环的速度非常快。你可能会感到惊讶。
我个人的偏好是故意引发异常并将其放在 try and 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 工具箱源代码之后,我实际上学会了所有这些东西。
MATLAB documentation 描述了 break
关键字:
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.
(我的重点)
如果要退出多个嵌套循环怎么办?其他语言,例如 Java,提供 labelled breaks,它允许您指定控制流将转移到哪里,但是 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 中)是什么?
对于您的 原始 特定 示例,我会说,而是使用线性索引和单个循环:
%// 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
我认为这个答案会因情况而异,并且没有通用的通用尺寸适合所有 惯用正确的 解决方案,但我会按照以下方式处理它,具体取决于您的问题(请注意,所有这些都假设矢量化解决方案不切实际,因为这是显而易见的首选)
- 减少嵌套的尺寸,不使用
break
或只使用一个break
(即如上所示)。 - Don't use break at all 因为除非你的谓词的计算很昂贵并且你的循环有很多次迭代,否则最后那些额外的迭代实际上应该是免费的。
- 失败 set a flag and break at each level。
- 或者最后将循环包装到函数中并调用
return
而不是break
。
据我所知,没有内置这样的功能。但是,在大多数情况下,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 是列繁重的,并且在大多数情况下使用多个循环将包括在非最佳维度上循环。矢量化解决方案不需要这样做,因为它们可以使用避免此类循环的智能方法(如果输入是行向量,这当然不成立,因此避免这种情况也很好)。
使用 Python(或您选择的毒药)的最佳惯用方法并忘记这一切,但这是另一回事。此外,我不再同意其他答案的矢量化声明。最近的 matlab 版本处理 for 循环的速度非常快。你可能会感到惊讶。
我个人的偏好是故意引发异常并将其放在 try and 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 工具箱源代码之后,我实际上学会了所有这些东西。