Разорвать внутреннюю петлю foreach и продолжить внешнюю петлю foreach - PullRequest
25 голосов
/ 17 ноября 2011

Если у меня есть вложенный цикл 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();
}

Ответы [ 8 ]

36 голосов
/ 17 ноября 2011

Как насчет использования флага?

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

  DoStuff();
}
22 голосов
/ 17 ноября 2011
foreach(var item in items)
{
  foreach(var otheritem in otheritems)
  {
    if (!double.TryParse(otheritem))
    {
      //...
      goto nextUpperLoop;
    }
  }

  DoStuff();
  nextUpperLoop: ;
}
18 голосов
/ 17 ноября 2011

Начните с написания лучшей версии 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();

Вместо того, чтобы пытаться понять, как перемещать управление, просто напишите код, который выглядит как логика . Если логика гласит: «Не делай вещи, если какой-либо из других элементов не анализируется как double», тогда используйте предикат Any, чтобы проверить все остальные элементы, чтобы увидеть, не разбирается ли какой-либо из них как double. Никаких петель, поэтому не нужно никакого необычного управления петлями.

Я был бы склонен пойти еще дальше; захватить логику в запросе, а затем повторить запрос:

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

foreach(var goodItem in goodItems)
    DoStuff(goodItem);
12 голосов
/ 17 ноября 2011

Простое - лучшее ...

  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 голосов
/ 17 ноября 2011

Вам нужна переменная для управления этим и, как вы говорите, выполните 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 голосов
/ 17 ноября 2011
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 голосов
/ 17 ноября 2011

Это не ясно из вашего фрагмента, но если вам нужно только искать непарсируемые значения в otheritems, тогда вы можете использовать LINQ:

foreach(var item in items)
{
  bool shouldISkip = otheritems.Any(otherItem => !double.TryParse(otherItem));
  if(shouldISkip) continue;
  DoStuff();
}
0 голосов
/ 17 ноября 2011

Iirc перерыв; оператор будет разрывать только ближайший цикл, поэтому выдает разрыв; во внутреннем цикле следует продолжить со следующего элемента во внешнем цикле.

...