web-dev-qa-db-fra.com

Briser la boucle foreach intérieure et continuer la boucle foreach extérieure

Si j'ai une boucle foreach imbriquée, comment puis-je rompre la boucle intérieure et dire à l'extérieur de continuer à ce point sans faire d'autre code en dessous de la boucle intérieure?

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();
}
28
Jon

Que diriez-vous d'utiliser un drapeau?

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

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

  DoStuff();
  nextUpperLoop: ;
}
24
BLUEPIXY

Commencez par écrire une meilleure version de Double.TryParse:

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

OK, vous avez maintenant quelque chose que vous pouvez facilement utiliser pour éliminer complètement la boucle intérieure, donc le problème disparaît:

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

Plutôt que d'essayer de comprendre comment déplacer le contrôle, il suffit d'écrire du code qui ressemble à la logique. Si la logique est "ne faites rien si aucun des autres éléments n'est analysé comme double", utilisez le prédicat Any pour tester tous les autres éléments pour voir si l'un d'eux n'analyse pas en double. Aucune boucle, donc aucun contrôle de boucle sophistiqué n'est nécessaire.

Je serais enclin à aller plus loin; capturer la logique dans une requête, puis itérer la requête:

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

foreach(var goodItem in goodItems)
    DoStuff(goodItem);
18
Eric Lippert

La simplicité est la meilleure ...

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

Une autre approche consiste à refactoriser:

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

return garantit que DoStuff ne se produit pas.

12
Marc Gravell

Vous avez besoin d'une variable pour contrôler cela et comme vous le dites .. faites un 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();
}
5
dknaack
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();
}
3
Jakub Konecki

Ce n'est pas clair à partir de votre extrait de code, mais si vous n'avez qu'à rechercher des valeurs non analysables dans otheritems, vous pouvez utiliser LINQ:

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

Iirc une pause; L'instruction rompra uniquement la boucle la plus proche, émettant ainsi une interruption; dans la boucle intérieure doit continuer avec l'élément suivant sur la boucle extérieure.

0
Anton