web-dev-qa-db-ja.com

内側のforeachループを解除し、外側のforeachループを続行する

入れ子になった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();
}
28
Jon

フラグを使用するのはどうですか?

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

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);
18
Eric Lippert

シンプルがベストです...

  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が発生しないようにします。

12
Marc Gravell

それを制御する変数が必要であり、あなたが言うように.. 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

スニペットからは明確ではありませんが、otheritemsで解析できない値のみを探す必要がある場合は、LINQを使用できます。

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

休憩してください。ステートメントは最も近いループのみを中断するため、breakを発行します。内側のループでは、外側のループの次のアイテムに続く必要があります。

0
Anton