打破内部foreach循环并继续外部foreach循环

35

如果我有一个嵌套的foreach循环,如何在中断内部循环并告诉外部从那个点继续而不执行内部循环下面的任何其他代码?

foreach(var item in items)
{
  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
      //break inner loop
      //continue outer loop so we never get to DoStuff()
    }
  }

  DoStuff();
}

6
我注意到这不是 double.TryParse 的签名。 - Eric Lippert
8个回答

47

可以考虑使用标志(flag)吗?

foreach(var item in items)
{
  bool flag = false;
  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
        flag = true;
        break;
    }
  }
  if(flag) continue;

  DoStuff();
}

35
foreach(var item in items)
{
  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
      //...
      goto nextUpperLoop;
    }
  }

  DoStuff();
  nextUpperLoop: ;
}

4
这可能是唯一合理的使用goto的情况。不过,我更喜欢Java通过为循环添加标签的方式来实现继续执行。 - arviman
1
@BLUEPIXY 我只是发牢骚,希望安德斯能够看到这个并在C#的下一个版本中实现它。希望吧,人总要有些希望。 - arviman
7
@BLUEPIXY - 请停止对其他社区成员的居高临下的态度。并不是有关你第一条评论中的“没有幽默标签”的任何人都这么说。感谢您合作,使这个社区更加友好。 - arviman

21

首先要编写一个更好的 Double.TryParse 版本:

static double? TryParseDouble(this string s)
{
    double d;
    return double.TryParse(s, out d) ? (double?)d : (double?)null;
}

好的,现在你有了一些可以轻松使用的东西,可以完全消除内部循环,所以问题就解决了:

foreach(var item in items)
    if (!otheritems.Any(otherItem=>otherItem.TryParseDouble() == null))
        DoStuff();

不要试图弄清楚如何控制代码流程,只需编写类似逻辑的代码。如果逻辑是“如果任何其他项目不能解析为双精度浮点数,则不执行操作”,则使用 Any 谓词测试所有其他项目,以查看它们中是否有任何一个无法解析为双精度浮点数。没有循环,所以不需要复杂的循环控制。

我倾向于更进一步;在查询中捕获逻辑,然后迭代查询:

var goodItems = from item in items
                where !item.OtherItems.Any(otherItem=>otherItem.TryParseDouble() == null))
                select item;

foreach(var goodItem in goodItems)
    DoStuff(goodItem);

3
虽然这条建议没有回答如何打破内部循环并继续外部循环的问题,但它是有用的。在这种情况下,您能够简化代码为单个循环,但并非总是如此。 - Kokodoko

12

简单就是最好的...

  bool doStuff = true;
  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
        doStuff = false;
        break;
    }
  }
  if(doStuff) DoStuff();

另一种方法是进行重构:

foreach(var outerItem in outerLoop) {
     Foo(outerItem);
}
...
void Foo(OuterItem item) {
    foreach(var innerItem in innerLoop) {
        if(someTest) return;
    }
    DoStuff();
}

return确保DoStuff不会发生。


5
你需要一个变量来控制这个,并像你所说的那样做一个“break”。
bool doStuff = true;
foreach(var item in items)
{
  doStuff = true;
  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
      doStuff = false;
      break;
    }
  }

  if (doStuff)
       DoStuff();
}

3
foreach(var item in items)
{
  var shouldContinue = false;

  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
      shouldContinue = true;
      //break inner loop
      //continue outer loop so we never get to DoStuff()
    }
  }

  if(shouldContinue)
     continue;

  DoStuff();
}

0

据我所知,break语句只会跳出最近的循环,因此在内部循环中发出break;应该会继续执行外部循环的下一项。


2
OP希望跳过外部循环中剩余的代码,并在外部循环的顶部继续执行。 - Merlyn Morgan-Graham

0

从你的片段中不清楚,但如果你只需要在otheritems中查找无法解析的值,那么可以使用LINQ:

foreach(var item in items)
{
  bool shouldISkip = otheritems.Any(otherItem => !double.TryParse(otherItem));
  if(shouldISkip) continue;
  DoStuff();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接