36

If I have a nested foreach loop how do I do break the inner loop and tell the outer to continue at that point without doing any other code below the inner loop?

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();
}
Jon
  • 38,814
  • 81
  • 233
  • 382

8 Answers8

47

How about using a 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();
}
Tudor
  • 61,523
  • 12
  • 102
  • 142
35
foreach(var item in items)
{
  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
      //...
      goto nextUpperLoop;
    }
  }

  DoStuff();
  nextUpperLoop: ;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • 4
    This is probably the only legitimate use of goto. I prefer java's way of continuing by labelling for loops though. – arviman Sep 16 '14 at 15:44
  • 1
    @BLUEPIXY I was just ranting in the tiny hope that Anders will read this and implement it in the next version of C#. Hope, a man can. – arviman Sep 17 '14 at 04:47
  • 7
    @BLUEPIXY - Please stop being patronizing towards other community members. It's not like anyone's saying "there's no humour tag" with regard to your first comment. Thank you for your cooperation in making this community more friendly. – arviman Sep 17 '14 at 13:30
21

Begin by writing a better version of Double.TryParse:

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

OK, now you have something you can easily use to eliminate the inner loop entirely, so the problem goes away:

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

Rather than try to figure out how to move control around, just write code that looks like the logic. If the logic is "don't do stuff if any of the other items do not parse as doubles", then use the Any predicate to test all the other items to see if any of them do not parse as doubles. No loops, so no fancy loop control needed.

I would be inclined to go a step further; capture the logic in a query, and then iterate the query:

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

foreach(var goodItem in goodItems)
    DoStuff(goodItem);
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 3
    Good advice, although it doesn't answer the question: how to break out of in inner loop, while continuing the outer? In this case you were able to simplify the code to a single loop, but that may not always be the case. – Kokodoko Mar 06 '16 at 14:32
12

Simple is best...

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

Another approach is to refactor:

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

The return ensures the DoStuff doesn't happen.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
5

You need a variable to controll that and like you say.. do a 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();
}
dknaack
  • 60,192
  • 27
  • 155
  • 202
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();
}
Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
0

Iirc a break; statement will only break the closest loop, so issuing a break; in the inner loop should continue with the next item on the outer loop.

Anton
  • 5,323
  • 1
  • 22
  • 25
0

It's not clear from your snippet, but if you only have to look for non-parseable values in otheritems then you can use LINQ:

foreach(var item in items)
{
  bool shouldISkip = otheritems.Any(otherItem => !double.TryParse(otherItem));
  if(shouldISkip) continue;
  DoStuff();
}
mamoo
  • 8,156
  • 2
  • 28
  • 38