如何在嵌套循环中终止外循环
本文关键字:终止 循环 嵌套循环 | 更新日期: 2023-09-27 17:58:13
在下面的例子中,终止所有嵌套循环的最佳方式是什么。一旦if语句为true,我想终止外部for语句(使用I)。换句话说,我需要整个循环停止。有比将I设置为10更好的方法吗?
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
break;
}
}
}
我会将其重构为一个方法,只要需要就调用return
。
您也可以使用goto
,而我曾为此使用过goto
,但这会引起不满。这是愚蠢的;这个场景是为什么它存在于语言中。
void DoSomeStuff()
{
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
return;
}
}
}
}
...somewhere else...
DoSomeStuff();
不要开枪打我,但这实际上可能需要一个goto:
for (int I = 0; I < 10; I++) {
for (int A = 0; A < 10; A++) {
for (int B = 0; B < 10; B++) {
if (something)
goto endOfTheLine;
}
}
}
endOfTheLine:
Console.WriteLine("Pure evilness executed");
假设您想退出所有循环,您可以将其重构为更结构化的东西:
bool done = false;
for (int i = 0; i < 10 && !done; i++) {
for (int a = 0; a < 10 && !done; a++) {
for (int b = 0; b < 10 && !done; b++) {
if (something) {
done = true;
continue;
}
}
}
}
如果循环体没有产生副作用,而只是在寻找"something"为true的第一个值,那么将通过首先消除所有循环来解决问题。
var query = from I in Enumerable.Range(0, 10)
from A in Enumerable.Range(0, 10)
from B in Enumerable.Range(0, 10)
where something(I, A, B)
select new { I, A, B };
var result = query.FirstOrDefault();
if (result == null)
{
Console.WriteLine("no result");
}
else
{
Console.WriteLine("The first result matching the predicate was {0} {1} {2},
result.I, result.A, result.B);
}
但如果循环有副作用,就不要这样做;查询是一个非常不适合放置副作用的地方。如果内环有副作用,那么你可以这样做:
var triples = from I in Enumerable.Range(0, 10)
from A in Enumerable.Range(0, 10)
from B in Enumerable.Range(0, 10)
select new { I, A, B };
foreach(var triple in triples)
{
if (something(triple.I, triple.A, triple.B))
break;
DoSomeSideEffect(triple.I, triple.A, triple.B);
}
现在只有一个循环可以突破,而不是三个。
为什么不这样做:
for (int I = 0; I < 10 || !something; I++)
{
for (int A = 0; A < 10 || !something; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
{
I=10;
break;
}
}
}
}
您总是可以利用for
中存在条件语句的事实,因此:
bool working = true;
for (int i=0; i<10 && working; i++)
{
for (int j=0; j<10 && working; j++)
{
for (int k=0; k<10 && working; k++)
{
Console.WriteLine(String.Format("i={0}, j={1}, k={2}", i,j,k));
if (i==5 && j==5 && k==5)
{
working = false;
}
}
}
}
我倾向于goto
,否则你将不得不退出每个循环:
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
break;
}
if (something)
break;
}
if (something)
break;
}
如果这是方法中的最后一个任务,则可以在条件为true时返回。否则,您必须将所有值设置为最大值
if (something)
{
I=10;
B=10;
A=10;
break;
}
for (int I = 0; I < 10; I++) {
for (int A = 0; A < 10; A++) {
for (int B = 0; B < 10; B++) {
if (something){
B=13;
A=13;
I=13;
}
}
}
}
一个非常原始的解决方案。
简单的解决方案是将嵌套循环重构为一个单独的方法,相关的返回类型是您当时想知道的任何类型:
在我的情况下,我假设你想要I、A和B的值,而不是Tuple。
// original method
...
var x = FindFirst()
...
// separate method
public Tuple<int,int,int> FindFirst()
{
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
return Tuple.Create(I,A,B);
}
}
}
return null;
}
如果需要将任何附加状态传递给方法(对于边界或something位),只需将它们作为参数传递即可。
如果你想以不同的方式处理找不到第一个的问题,那么就用这样的方式
bool TryFindFirst(out Tuple<int,int,int> x)
将是一个替代方案。
顺便说一句,在c#(和许多其他语言)中,使用大写字母作为变量名(尤其是单字母)被认为是糟糕的风格。
我不知道C#
是否支持它,但有些语言支持:
break n;
其中n
是要中断的嵌套循环数。
您总是可以满足循环的期望:
如果(某事)B=10
编辑:(看起来你通过编辑将其包含在你的帖子中)
如果你不喜欢它的外观,你可以包装一个函数,比如:
满足(B,10)
然后它看起来更干净,但确实不需要。
另一种可能性是在所有for循环中级联对isSomething的检查。你添加
if (something)
break;
在所有3个循环中
就我个人而言,我会使用上面的Paxdiablo方法(+1),但下面是另一种选择-这取决于OP是否需要知道当"something"为真时I、A和B的数字是什么,因为我猜iab是在循环中声明的。
bool done = false;
int i, a, b;
for (i = 0; i < 10 ; i++) {
for (a = 0; a < 10 ; a++) {
for (b = 0; b < 10 ; b++) {
if (something) {
done = true;
break;
}
}
if (done) break;
}
if (done) break;
}
// i, a and B are set to the last numbers where "something" was true