如何在嵌套循环中终止外部循环?

时间:2011-06-01 12:20:52

标签: c# loops nested-loops

在下面的示例中,终止所有嵌套循环的最佳方法是什么。一旦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;
        }
    }
}

14 个答案:

答案 0 :(得分:32)

我会将此重构为方法,只需在需要时调用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();

答案 1 :(得分:15)

不要拍我,但这实际上可能需要一个转到:

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

答案 2 :(得分:14)

假设您要退出所有循环,您可以将其重构为更结构化的内容:

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

答案 3 :(得分:10)

如果循环体不产生副作用,而只是寻找“某事物”为真的第一个值,那么可以通过首先消除所有循环来解决问题。

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

现在只有一个循环可以突破,而不是三个。

答案 4 :(得分:3)

为什么不这样做:

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

答案 5 :(得分:3)

您总是可以利用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;
            }
        }
    }
}

答案 6 :(得分:2)

我会倾向于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;
    }

答案 7 :(得分:2)

如果这是方法中的最后一项任务,则可以在条件为真时返回。 否则你必须将所有值都设为最大值

if (something)              
    {
        I=10;   
        B=10;
        A=10;
        break;
    }

答案 8 :(得分:2)

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

非常原始的解决方案。

答案 9 :(得分:2)

简单的解决方案是将嵌套循环重构为一个单独的方法,相关的返回类型就是你想知道的那一点:

在我的情况下,我会假设你想要那个时候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;
}

如果您需要将任何其他状态传递给方法(对于边界或某些位),只需将它们作为参数传递。

如果你想处理以不同的方式找不到第一个,那么

bool TryFindFirst(out Tuple<int,int,int> x) 

将成为候补。

作为使用大写字母表示变量名称(特别是单字母)的旁注,在c#(和许多其他语言)中被认为是不好的风格

答案 10 :(得分:2)

我不知道C#是否支持它,但有些语言支持:

break n;

其中 n 是要中断的嵌套循环的数量。

答案 11 :(得分:1)

你总能满足循环期望:

if(something)   B = 10

编辑:(看来您通过编辑将其包含在帖子中)

如果您不喜欢它的外观,可以包装一个函数,例如:

满足式(B,10)

然后它看起来更干净,但实际上并不需要。

答案 12 :(得分:1)

另一种可能性是对所有for循环中的isSomething进行级联检查。 你添加

if (something)                         
   break; 
所有3个循环中的

答案 13 :(得分:1)

就我个人而言,我会选择上面的Paxdiablo方法(+1为此),但另一种选择在下面 - 这取决于当“某事”是真的时,OP需要知道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