如何在c#中从第二个嵌套的foreach循环中打破第一个foreach循环

时间:2016-03-02 12:00:18

标签: c#

如何在c#中为每个循环的第二个嵌套中的每个循环首先打破,我想在每个循环中检查第二个中的某些条件然后尝试打破每个循环的父级

foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
                break;//but want to break first foreach loop
          }
     }
}

6 个答案:

答案 0 :(得分:4)

快速回答:

foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
                goto end; // I'd probably add a comment here
          }
     }
     // *1
}
end:
{} // the rest of your code.

但是,但SESE ......

SESE违规违反了单一条目退出原则。通过使用额外的条件,它很容易修复:

bool found = false;
for (int i=0; i<foo.Count && !found; ++i)
{
    for (int j=0; j<bar.Count; ++j) 
    {
        if (...) { found = true; }
    }
    // *1 
    if (!found) { ... }
}

为什么在这里使用GOTO?

我相信创建适当的,可维护的代码意味着您使用最能描述您意图的语言结构。这里的“代码”总是由两件事组成:

  • 控制流程,通过forwhilebreakgoto之类的内容表达。
  • 数据流,通过表达式,变量和其他内存访问来表达。

OP的目的是打破嵌套循环,这相当于控制流操作。因此,我认为你应该使用最能代表意图的控制流程操作 - 在这种情况下是goto

请注意,这并不是您应该滥用以在所有地方引入goto语句的原因;如果你这样做,代码将变得非常难以阅读,这与可维护性和可读性无关。您应该将goto语句视为“最后的控制流”语句,该语句在正确编写的代码中很少使用。

那就是说,在这种情况下,这意味着你不应该创建局部变量来处理控制流,除非这是绝对必要的(例如,如果没有可用的语言结构可以清楚地表达你的意图)。出于同样的原因,我不会在这种特殊情况下使用Linq。

我想要表现。我该怎么办?

我认为大多数滥用语言结构的原因是不了解编译器如何处理代码,这就是为什么我习惯于解释内部工作原理的部分原因。请记住,我建议使用goto,因为它最清楚地描述了您的意图,而不是因为它可能会更快一些。这是:

想象一下编译器。您的代码中的代码为* 1时有大量代码,无法使用return。现在有两种选择:

  1. 您可以使用转到。
  2. 您可以使用额外标志。
  3. 选项1将编译为具有内存的字段。内存是“稀疏的”,因为编译器会尽可能地消耗尽可能少的内存,最好是寄存器。这就是你的表演源自的地方。因此,编译器将尝试消除该标志。

    为此,您的编译器将进行大量的流分析和其他工作,试图确定实际上有两个代码路径:一个是设置标志的时候和另一个,如果不是。

    现在,如果你很幸运,编译器会有'aha'时刻并将你的代码从(2)​​更改为简单的GOTO,在这种情况下,天空仍然是蓝色的,每个人都很高兴。

    但是,如果你不幸运(并且有很多实际原因会发生这种情况),它将不会从流量分析中检测到这一点,也不会创建GOTO。由于您的标志在内部循环中使用,它甚至可能为此分配一个寄存器,这可能是最糟糕的情况。

    如果您首先使用goto,则不需要所有这些。您只需为编译器提供正确的解决方案。简单。

    你有没有关于编译器如何做到这一点的更多细节?

    是的,看看这个2小时的Chandler视频,它解释了编译器的工作原理:https://www.youtube.com/watch?v=FnGCDLhaxKU

    -updated - 显然有些人误解了我的故事,正如@Groo指出的那样。我做了一些调整,以澄清我的意思。

答案 1 :(得分:4)

你可以使用'flag'

这样做
bool breakout = false
foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
             breakout = true;
             break;
          }
     }
     if(breakout)
      break;
}

答案 2 :(得分:3)

您可以尝试使用return,如下所示:

foreach(//do some stuff)
    foreach(//do some stuff)
       if(//check some condition)
          return;

答案 3 :(得分:3)

如果你不能return,我建议使用 Linq ,它会使你的代码可读

Boolean found = false;

foreach(var item1 in source1.TakeWhile(_ => !found)) {
     foreach(var item2 in source2.TakeWhile(_ => !found)) {
          if (some condition)
          {
               found = true;

               //break; // Not necessary
          }
     }
}

答案 4 :(得分:1)

bool doBreak = false;
foreach(//do some stuff)
{
    foreach(//do some stuff)
    {
        doBreak = <check some condition>;
        if(doBreak) break;
    }
    if(doBreak) break;
}

答案 5 :(得分:1)

您可以使用 WHILE 。也许这段代码对你有帮助

Map<List<Integer>,Integer[]> WEIGHTS = ...
WEIGHTS.put(Arrays.asList(new Integer[]{0,0,0,0,0}), new Integer[]{20,20,15,15,10,10,5,5});
List<Integer> sheriffAndBanditPositions = Arrays.asList(new Integer[]{0,0,0,0,0});
probabilities = WEIGHTS.get(sheriffAndBanditPositions);