ネストされたループから抜け出す


216

forループが別のループ内にネストされている場合、両方のループ(内側と外側)から可能な限り最速で効率的に抜け出すにはどうすればよいですか?

ブール値を使用する必要はなく、別のメソッドに移動する必要があるのではなく、外側のループの後にコードの最初の行を実行するだけです。

これをすばやく簡単に行う方法は何ですか?

例外は安くなくて、本当に例外的な状況でのみスローされるべきだと思っていました。したがって、このソリューションはパフォーマンスの観点からは良いとは思いません。

.NETの新しい機能(anonメソッド)を利用して、かなり基本的なことを行うのが適切だとは思いません。


確認したいのですが、なぜこれをしたいのですか?
Jon Limjap 2008

3
ブール値を使用したくないのですか?それを行うことの何が問題になっていますか?
アンソニー

VB.netでは、try / finallyステートメント(catchなし)を任意の数のループにラップすることができます。その後、「exit try」ですべてのループを終了します。
Brain2000

回答:


206

まあ、gotoしかし、それは醜く、常に可能であるとは限りません。ループをメソッド(または非メソッド)に配置returnして、メインコードに戻るために使用することもできます。

    // goto
    for (int i = 0; i < 100; i++)
    {
        for (int j = 0; j < 100; j++)
        {
            goto Foo; // yeuck!
        }
    }
Foo:
    Console.WriteLine("Hi");

対:

// anon-method
Action work = delegate
{
    for (int x = 0; x < 100; x++)
    {
        for (int y = 0; y < 100; y++)
        {
            return; // exits anon-method
        }
    }
};
work(); // execute anon-method
Console.WriteLine("Hi");

C#7では「ローカル関数」を取得する必要があることに注意してください。これは(構文tbdなど)、次のように機能することを意味します。

// local function (declared **inside** another method)
void Work()
{
    for (int x = 0; x < 100; x++)
    {
        for (int y = 0; y < 100; y++)
        {
            return; // exits local function
        }
    }
};
Work(); // execute local function
Console.WriteLine("Hi");

49
このタイプの状況では、gotoの使用が通常のbreakなどの使用よりも悪いとは思いません(結局、どちらもラベルへの無条件分岐であり、breakを使用するとラベルが暗黙的になるだけです)。
グレッグビーチ、

37
gotoは他の方法よりも

7
@BeowulfOF-内側のループと外側のループではなく、内側のループから抜け出すだけです。
グレッグビーチ、

36
後藤自体は醜くない。醜いのはgotoを悪用してスパゲッティコードを生成することです。ネストされたループから抜け出すためにgotoを使用することは完全に問題ありません。さらに、構造的プログラミングの観点から見ると、すべての中断、継続、および復帰はgotoよりも優れているわけではないことに注意してください。そのため、純粋な構造化言語(オリジナルのPascalなど)には3つすべてが欠けています。
el.pescado 2010

11
@ el.pescadoは完全に右である:多くのプログラマーが信じるように誤解されているgoto有害なそれ自体は、単にである一方で、正確ないくつかのことを行うための機器、および多くの楽器のように悪用されることがあります。この宗教的嫌悪gotoは率直に言って非常に愚かで、間違いなく非科学的です。
o0 '。

96

Cでよく使用されるアプローチのC#への適合-ループ条件の外側にある外部ループの変数の値を設定します(つまり、int変数を使用するforループINT_MAX -1がよく選択されます)。

for (int i = 0; i < 100; i++)
{
    for (int j = 0; j < 100; j++)
    {
        if (exit_condition)
        {
            // cause the outer loop to break:
            // use i = INT_MAX - 1; otherwise i++ == INT_MIN < 100 and loop will continue 
            i = int.MaxValue - 1;
            Console.WriteLine("Hi");
            // break the inner loop
            break;
        }
    }
    // if you have code in outer loop it will execute after break from inner loop    
}

コードの注記でbreakは、外側のループの次の反復に魔法のようにジャンプすることはないので、内側のループの外側にコードがある場合、このアプローチにはさらにチェックが必要です。このような場合は、他の解決策を検討してください。

このアプローチはforand whileループで機能しますが、では機能しませんforeach。以下の場合はforeach(あなたができたとしても、あなたはそれを変更することはできませんのでご隠さ列挙子へのコードアクセスを持っていないだろうIEnumeratorいくつかの「MoveToEnd」メソッドを持っていません)。

インラインコメントの作者への謝辞: メタ
i = INT_MAX - 1による提案/ ygoeによるコメント。
forforeach
適切なjmbpianoにIntMaxよるblizpasta による
内部ループ後のコードに関するコメント


@DrG:C#では「breakステートメントは、それが出現する最も近い囲みループまたはswitchステートメントを終了させます」として機能しません。(msdn)
blizpasta

1
@blizpastaそれで?彼が外側のループの条件をfalseにすると(そうしたように)、両方から抜けます。
Patrick

51
i = INT_MAX-1;を使用する必要があります。それ以外の場合はi ++ == INT_MIN <100でループは継続します
Meta

6
foreachのアイデアは?
ktutnik 2013年

4
@ktutnik非表示の列挙子へのコードアクセス権がないため、foreachでは機能しません。また、IEnumeratorには「MoveToEnd」メソッドがありません。
ygoe 2014年

39

このソリューションはC#には適用されません

他の言語、Javascript、Java、Dでこの質問を見つけた人は、ラベル付きの改行を許可して続行します。

outer: while(fn1())
{
   while(fn2())
   {
     if(fn3()) continue outer;
     if(fn4()) break outer;
   }
}

40
悲しいことに、これはc#では実行できません。多くの場合、よりクリーンなコードが生成されます。
リッカード

17
これがC#向けではないことに気づくまで、私は実際に一瞬興奮しました。:(
Arvo Bowen

1
この概念は、誰かがそこで問題に遭遇した場合のPowerShellにも当てはまります。(ラベル名の前にコロンを付けるだけです。)これはPowerShell固有ではないことを知っています...この構文は、C#で使用できるgotoラベルと互換性がありません。PHPは別のものを使用します。breakステートメントの後にレベル数を置きます。
ygoe 2014年

1
これはC#ではなくJavaです
Luca Ziegler

この機能をC#で表示したい場合は、ここに評価を配置してください。😉github.com /dotnet
csharplang

28

外側のループに適切なガードを使用してください。ブレークする前に、内側のループにガードを設定します。

bool exitedInner = false;

for (int i = 0; i < N && !exitedInner; ++i) {

    .... some outer loop stuff

    for (int j = 0; j < M; ++j) {

        if (sometest) {
            exitedInner = true;
            break;
        }
    }
    if (!exitedInner) {
       ... more outer loop stuff
    }
}

あるいは、内部ループをメソッドに抽象化し、falseが返されたときに外部ループを終了します。

for (int i = 0; i < N; ++i) {

    .... some outer loop stuff

    if (!doInner(i, N, M)) {
       break;
    }

    ... more outer loop stuff
}

4
OPが「ブール値を使用する必要がない」と述べた場合を除きます。
LeopardSkinPillBoxHat 2008年

非常にパスカルっぽいです…私はおそらく後藤を使いたいと思います。
ジョナサンレフラー

21

これについては引用しないでください。gotoを使用できます。MSDNで提案されているようにを。両方のループの各反復でチェックされるフラグを含めるなど、他の解決策があります。最後に、問題の非常に重い解決策として例外を使用できます。

GOTO:

for ( int i = 0; i < 10; ++i ) {
   for ( int j = 0; j < 10; ++j ) {
      // code
      if ( break_condition ) goto End;
      // more code
   }
}
End: ;

状態:

bool exit = false;
for ( int i = 0; i < 10 && !exit; ++i ) {
   for ( int j = 0; j < 10 && !exit; ++j ) {
      // code
      if ( break_condition ) {
         exit = true;
         break; // or continue
      }
      // more code
   }
}

例外:

try {
    for ( int i = 0; i < 10 && !exit; ++i ) {
       for ( int j = 0; j < 10 && !exit; ++j ) {
          // code
          if ( break_condition ) {
             throw new Exception()
          }
          // more code
       }
    }
catch ( Exception e ) {}

2
これらはすべて、メソッドに因数分解して早期リターンを使用するのが非常にクリーンなハックな回避策です
Dustin Getz '28

3
:)右、それは簡単な解決策ですが、引数としてメソッドに必要なすべてのローカルデータを渡す必要があります...これは、後藤は、適切な解決策になるかもしれない数少ない場所の一つです
デビッド・ロドリゲス- dribeas

内側のループを終了した後、外側のループを終了する前に「追加のコード」が1回実行されるため、Conditionメソッドは機能しません。GOTOメソッドは機能しますが、投稿者が望んでいないことを正確に実行します。Exceptionメソッドは機能しますが、GOTOよりも醜くて遅いです。
Windowsプログラマ

ラベルの後にそのセミコロンを強調表示します。このようにして、そのラベルはブロックの最後にも配置できます。+1
タマスヘゲダス2016年

@Windowsprogrammer OPは、「これをすばやく簡単に行う方法は何ですか?」と尋ねました。後藤が推奨されるソリューションです。別のメソッドを使用せずに、簡潔で簡潔なものにします。
Suncat2000

16

ネストされたforループをプライベートメソッドにリファクタリングすることは可能ですか?これにより、メソッドから単純に「戻る」ことでループを終了できます。


オリジナルのメソッドを短くするという副次的な利点があります:-)
Martin Capodici

C ++ 11件のラムダは、簡単にいくつかのケースのためにこれを行います[&] { ... return; ... }();
BCS

14

goto声明が嫌いな人が多いようで、少し正直する必要があると感じました。

私は「感情」の人々が、goto結局はコードの理解と、考えられるパフォーマンスへの影響について(誤解)まで煮詰められると信じています。質問に答える前に、まず、それがどのようにコンパイルされるかについての詳細のいくつかを説明します。

ご存じのとおり、C#はILにコンパイルされ、ILはSSAコンパイラーを使用してアセンブラーにコンパイルされます。これがどのように機能するかについて少し洞察を与えてから、質問自体に答えてみましょう。

C#からILへ

まず、C#コードが必要です。簡単に始めましょう:

foreach (var item in array)
{
    // ... 
    break;
    // ...
}

フードの下で何が起こるかについての良い考えをあなたに与えるために、私は一歩ずつこれを行います。

最初の変換:からforeach同等のforループへ(注:ここでは配列を使用しています。IDisposableの詳細を知りたくないためです。この場合、IEnumerableも使用する必要があります):

for (int i=0; i<array.Length; ++i)
{
    var item = array[i];
    // ...
    break;
    // ...
}

2番目の翻訳:forおよびbreakは、より簡単な同等物に翻訳されます。

int i=0;
while (i < array.Length)
{
    var item = array[i];
    // ...
    break;
    // ...
    ++i;
}

そして3番目の変換(これはILコードに相当します):ブランチに変更breakwhileます。

    int i=0; // for initialization

startLoop:
    if (i >= array.Length) // for condition
    {
        goto exitLoop;
    }
    var item = array[i];
    // ...
    goto exitLoop; // break
    // ...
    ++i;           // for post-expression
    goto startLoop; 

コンパイラーはこれらのことを1つのステップで実行しますが、プロセスについての洞察を提供します。C#プログラムから進化したILコードは、最後のC#コードの文字変換です。あなたはここで自分のために見ることができます:https//dotnetfiddle.net/QaiLRz( 'view IL'をクリックして)

ここで確認したことの1つは、プロセス中にコードがより複雑になることです。これを観察する最も簡単な方法は、同じことを達成するためにますます多くのコードが必要になるという事実によるものです。また、、、およびは実際にはの省略形であると主張するforeach場合もありますが、これは部分的に当てはまります。forwhilebreakgoto

ILからアセンブラーへ

.NET JITコンパイラはSSAコンパイラです。ここでは、SSAフォームの詳細や最適化コンパイラーの作成方法については詳しく説明しません。多すぎますが、何が起こるかについての基本的な理解は得られます。理解を深めるには、コンパイラの最適化について読み始めることをお勧めします(簡単な紹介として、この本を気に入っています:http : //ssabook.gforge.inria.fr/latest/book.pdf //ssabook.gforge.inria.fr/latest/book.pdf)とLLVM(llvm.org)を。

すべての最適化コンパイラは、コードが簡単予測可能なパターンに従うという事実に依存しています。FORループの場合、グラフ理論を使用して分岐を分析し、次に分岐内のcycliなどを最適化します(たとえば、後方分岐)。

ただし、ループを実装するための前方分岐があります。ご想像のとおり、これは実際には次のように、JITが修正する最初のステップの1つです。

    int i=0; // for initialization

    if (i >= array.Length) // for condition
    {
        goto endOfLoop;
    }

startLoop:
    var item = array[i];
    // ...
    goto endOfLoop; // break
    // ...
    ++i;           // for post-expression

    if (i >= array.Length) // for condition
    {
        goto startLoop;
    }

endOfLoop:
    // ...

ご覧のとおり、これで後方ループができました。これが小さなループです。ここでまだ厄介なのは、私たちのbreak声明が原因で最終的に分岐したブランチだけです。これを同じ方法で移動できる場合もありますが、そのままにしておく場合もあります。

では、なぜコンパイラはこれを行うのでしょうか?ループを展開できれば、ベクトル化できるかもしれません。定数が追加されていることを証明できる場合もあります。つまり、ループ全体が薄い空気に消えてしまう可能性があります。要約すると:(分岐を予測可能にすることで)パターンを予測可能にすることで、特定の条件がループに保持されていることを証明できます。つまり、JIT最適化中に魔法をかけることができます。

しかし、ブランチはこれらの素晴らしい予測可能なパターンを壊す傾向があります。それは、オプティマイザが何か嫌いなことです。Break、continue、goto-これらはすべて、これらの予測可能なパターンを破ることを意図しているため、実際には「良い」ものではありません。

また、この時点で、単純なforeach方が予測しやすいこと、そしてあちこちにある一連のgotoステートメントよりも理解しやすいことも理解する必要があります。(1)可読性と(2)オプティマイザーの観点からは、どちらも優れたソリューションです。

言及する価値のあるもう1つの点は、レジスタを変数に割り当てるコンパイラの最適化(レジスタ割り当てと呼ばれるプロセス)に非常に関連があることです。ご存知かもしれませんが、CPUには限られた数のレジスタしかなく、ハードウェアのメモリの中で最速のメモリです。最も内側のループにあるコードで使用される変数は、レジスターが割り当てられる可能性が高くなりますが、ループ外の変数はそれほど重要ではありません(このコードはおそらくヒットが少ないため)。

助けて、あまりにも複雑...どうすればいいですか?

肝心な点は、常に自由に使用できる言語構造を使用する必要があるということです。これにより、通常(暗黙的に)コンパイラーの予測可能なパターンが構築されます。可能な場合は奇妙な枝を避けるようにしてください(特に:breakcontinuegotoまたはreturn何の真ん中で)。

ここでの朗報は、これらの予測可能なパターンが読みやすく(人間の場合)、簡単に見つけられる(コンパイラの場合)ことです。

これらのパターンの1つは、SESEと呼ばれます。これは、単一エントリー、単一出口を表しています。

そして今、私たちは本当の質問に行きます。

次のようなものがあるとします。

// a is a variable.

for (int i=0; i<100; ++i) 
{
  for (int j=0; j<100; ++j)
  {
     // ...

     if (i*j > a) 
     {
        // break everything
     }
  }
}

これを予測可能なパターンにする最も簡単な方法は、単純にif完全に排除することです。

int i, j;
for (i=0; i<100 && i*j <= a; ++i) 
{
  for (j=0; j<100 && i*j <= a; ++j)
  {
     // ...
  }
}

他の場合では、メソッドを2つのメソッドに分割することもできます。

// Outer loop in method 1:

for (i=0; i<100 && processInner(i); ++i) 
{
}

private bool processInner(int i)
{
  int j;
  for (j=0; j<100 && i*j <= a; ++j)
  {
     // ...
  }
  return i*j<=a;
}

一時変数?良い、悪い、または醜い?

ループ内からブール値を返すように決定することもできます(ただし、個人的にはSESE形式を好みます。これは、コンパイラーがそれを表示する方法であり、読みやすくなるためです)。

一部の人々は、一時変数を使用する方がきれいだと思い、次のような解決策を提案します。

bool more = true;
for (int i=0; i<100; ++i) 
{
  for (int j=0; j<100; ++j) 
  {
     // ...
     if (i*j > a) { more = false; break; } // yuck.
     // ...
  }
  if (!more) { break; } // yuck.
  // ...
}
// ...

私は個人的にこのアプローチに反対しています。コードのコンパイル方法をもう一度見てください。これがこれらの素晴らしい予測可能なパターンで何をするかを考えてみましょう。写真をゲット?

そうです、私にそれを綴らせてください。何が起こるか:

  • コンパイラーはすべてをブランチとして書き出します。
  • 最適化ステップとして、コンパイラーはデータフロー分析を行い、moreたまたま制御フローでのみ使用される奇妙な変数を削除しようとします。
  • 成功した場合、変数moreはプログラムから削除され、ブランチのみが残ります。これらのブランチは最適化されるため、内側のループから1つのブランチのみが取得されます。
  • 失敗した場合、変数moreは最も内側のループで確実に使用されるため、コンパイラーが変数を最適化しないと、レジスターに割り当てられる可能性が高くなります(貴重なレジスターメモリを消費します)。

つまり、要約すると、コンパイラのオプティマイザはmore、制御フローにのみ使用されていることを理解するために多くのトラブルに巻き込まれ、最良のケースでは、それを外部の外側の単一のブランチに変換しますループ。

言い換えれば、最良のシナリオは、これと同等のものになることです。

for (int i=0; i<100; ++i) 
{
  for (int j=0; j<100; ++j)
  {
     // ...
     if (i*j > a) { goto exitLoop; } // perhaps add a comment
     // ...
  }
  // ...
}
exitLoop:

// ...

これに関する私の個人的な意見は非常に単純です。これが私たちがずっと意図していたことである場合、コンパイラと可読性の両方について世界をより簡単にし、それをすぐに書いてみましょう。

tl; dr:

結論:

  • 可能であれば、forループで単純な条件を使用します。可能な限り高水準の言語構造に固執してください。
  • すべてが失敗し、gotoまたはのどちらかが残っている場合bool moreは、前者を優先してください。

OTOH:私はめったに外側のループを壊したり、goto-equiv(そして間違いなくもっときれいに書けるコードがたくさんある)を望んだりしますが、他のドメインではもっと一般的かもしれませんが、今日はそうだったでしょう。しかし、それは主にによるものyield returnでした。つまり、いくつかの有用なケースがあることを示すのは簡単ですが、ほとんどの「アプリケーションレベル」のコードでは、C / C ++からのフラストレーションの発生が非常に少ないため、「C / C ++から来るもの」を除いて、おそらく見落としがちです。 Rubyはこのドメインにも当てはまるため、場合によっては「スロー」(例外の巻き戻しではない)をスローします。
user2864740 2017年

1
@ Suncat2000を使用gotoしないように変数や条件分岐などのコードを追加しても、コードが読みやすくなるわけではありません-何が起こるかは正反対です。実際、制御フローにはより多くのノードが含まれます-これはかなりです複雑さの定義。自己規律を支援するためにそれを単に回避することは、読みやすさの点で非生産的な音に聞こえます。
atlaste

@atlaste:申し訳ありませんが、私のコメントをより明確に述べさせてください。私が言っておくべきだったのは、いい説明でした。しかし、gotoを回避する人々はパフォーマンスについてではありません。読みやすさの原因となる悪用を回避することです。私たちは、gotoそれを乱用しないという規律を持っていないだけの人々を想定することができます。
Suncat2000

@atlaste、「無意味」な言語は何ですか?
パセリエ

11

関数/メソッドを考慮して早期リターンを使用するか、ループをwhile句に再配置します。goto / exceptions / whateverはここでは確かに適切ではありません。

def do_until_equal():
  foreach a:
    foreach b:
      if a==b: return

10

あなたは、素早く、素晴らしい、ブール値を使わない、gotoを使わない、C#の組み合わせを求めました。あなたはあなたが望むことをするためのすべての可能な方法を除外しました。

最も早くて醜い方法はgotoを使うことです。


完全に同意する。単一のgotoを取り除くためだけに新しいメソッドを導入するのはばかげています。コンパイラが何らかの理由でそのメソッド呼び出しをインライン化できない場合、余分なメソッド呼び出しによる完全に不要なオーバーヘッドが発生します。ループを解除するためだけに例外をスローしてキャッチすることは、どちらも冗長であり、途方もなく高価です。
Zar Shardan

@Windowsprogramm:OPは「gotoの使用なし」を要求しませんでした。彼は「別の方法に行きたい」とは思わなかった。問題はすべての可能な方法を除外することにはほど遠かったですが、gotoがここで最良であることを暗示するのは正しいことです。
Suncat2000

5

コードをそれ自体の関数に抽象化し、早期復帰を使用するよりも良い場合があります。ただし、早期復帰は悪です:)

public void GetIndexOf(Transform transform, out int outX, out int outY)
{
    outX = -1;
    outY = -1;

    for (int x = 0; x < Columns.Length; x++)
    {
        var column = Columns[x];

        for (int y = 0; y < column.Transforms.Length; y++)
        {
            if(column.Transforms[y] == transform)
            {
                outX = x;
                outY = y;

                return;
            }
        }
    }
}

1
しかし、これによりOPが要求する従来の解決策が可能になります
Surya Pratap 2014

2

「break」を使用する例をたくさん見ましたが、「continue」を使用する例はありません。

それでも、内部ループにある種のフラグが必要になります。

while( some_condition )
{
    // outer loop stuff
    ...

    bool get_out = false;
    for(...)
    {
        // inner loop stuff
        ...

        get_out = true;
        break;
    }

    if( get_out )
    {
        some_condition=false;
        continue;
    }

    // more out loop stuff
    ...

}

1

break数十年前にCで初めて見たので、この問題は私を悩ませてきました。私はいくつかの言語拡張が壊れる拡張機能を持ち、こうして機能することを望んでいました:

break; // our trusty friend, breaks out of current looping construct.
break 2; // breaks out of the current and it's parent looping construct.
break 3; // breaks out of 3 looping constructs.
break all; // totally decimates any looping constructs in force.

3
次に、メンテナンスプログラマは別のレベルのネストを挿入し、一部のbreakステートメントを修正し、他の一部のbreakステートメントを壊します。そのための修正は、代わりにラベルを壊すことです。これは本当に提案されていますが、実用主義者は代わりにラベルにgotoを使用します。
Windowsプログラマー、

待って、もうメンテナンスプログラミングをしているのは誰ですか?:)
ジェシーC.スライサー、

2
JavaScriptには、blocks / breakステートメントにもラベルが付けられています。devguru.com/Technologies/ecmascript/quickref/break.html
デビッドグラント

@クリス・バートー:クール!私のクリスマスを作った:) @David Grant:JSブレーク== Cの後藤のようですか?
ジェシーC.スライサー、

Dはbreak / continuesにラベルを付けました
BCS

0

学生時代から、gotoがなくてもコードで何でもできることが数学的に証明可能であると言われていました(つまり、gotoが唯一の答えである状況はありません)。だから、私はgotoを決して使用しません(私個人の好みだけで、私が正しいか間違っているかを示唆していません)

とにかく、ネストされたループから抜け出すには、次のようにします。

var isDone = false;
for (var x in collectionX) {
    for (var y in collectionY) {
        for (var z in collectionZ) {
            if (conditionMet) {
                // some code
                isDone = true;
            }
            if (isDone)
                break;
        }
        if (isDone) 
            break;
    }
    if (isDone)
        break;
}

...私が私のような人たちの反ゴト「ファンボーイ」であることを願っています:)


申し訳ありませんが、あなたの講師はあなたの状態のせいです。彼があなたにアセンブリを学ぶことを強制することを気にかけたなら、あなたは 'goto'が単なるジャンプであることを知っています(もちろん私はこれがC#の質問であることを無視しています)。
cmroanirgo 2016

0

それが私がやった方法です。まだ回避策です。

foreach (var substring in substrings) {
  //To be used to break from 1st loop.
  int breaker=1;
  foreach (char c in substring) {
    if (char.IsLetter(c)) {
      Console.WriteLine(line.IndexOf(c));
      \\setting condition to break from 1st loop.
      breaker=9;
      break;
    }
  }
  if (breaker==9) {
    break;
  }
}


0

ダブルループを終了する最も簡単な方法は、最初のループを直接終了することです

string TestStr = "The frog jumped over the hill";
char[] KillChar = {'w', 'l'};

for(int i = 0; i < TestStr.Length; i++)
{
    for(int E = 0; E < KillChar.Length; E++)
    {
        if(KillChar[E] == TestStr[i])
        {
            i = TestStr.Length; //Ends First Loop
            break; //Ends Second Loop
        }
    }
}

これは、breakを使用して内側のループを終了するため機能しません。外側のループは繰り返し続けます。
Alex Leo

0

ループは、ループ内のカスタム条件を使用して分割できるため、クリーンなコードを使用できます。

    static void Main(string[] args)
    {
        bool isBreak = false;
        for (int i = 0; ConditionLoop(isBreak, i, 500); i++)
        {
            Console.WriteLine($"External loop iteration {i}");
            for (int j = 0; ConditionLoop(isBreak, j, 500); j++)
            {
                Console.WriteLine($"Inner loop iteration {j}");

                // This code is only to produce the break.
                if (j > 3)
                {
                    isBreak = true;
                }                  
            }

            Console.WriteLine("The code after the inner loop will be executed when breaks");
        }

        Console.ReadKey();
    }

    private static bool ConditionLoop(bool isBreak, int i, int maxIterations) => i < maxIterations && !isBreak;   

このコードにより、次の出力が得られます。

  • 外部ループ反復0
  • 内部ループ反復0
  • 内部ループ反復1
  • 内部ループ反復2
  • 内部ループ反復3
  • 内部ループ反復4
  • 内側のループの後のコードは、ブレーク時に実行されます

0

もう1つのオプションは、自己呼び出しの無名関数です。goto、label、新しい変数、新しいfunction-nameは使用せず、最初の匿名メソッドの例よりも1行短い。

// self-invoked-anonymous-function
new Action(() =>
{
    for (int x = 0; x < 100; x++)
    {
        for (int y = 0; y < 100; y++)
        {
            return; // exits self invoked lambda expression
        }
    }
})();
Console.WriteLine("Hi");

-3

外部ループを発生させるカスタム例外をスローします。

それはforforeachまたは、whileまたは任意の種類のループと、try catch exceptionブロックを使用する任意の言語で機能します

try 
{
   foreach (object o in list)
   {
      foreach (object another in otherList)
      {
         // ... some stuff here
         if (condition)
         {
            throw new CustomExcpetion();
         }
      }
   }
}
catch (CustomException)
{
   // log 
}

-4
         bool breakInnerLoop=false
        for(int i=0;i<=10;i++)
        {
          for(int J=0;i<=10;i++)
          {
              if(i<=j)
                {
                    breakInnerLoop=true;
                    break;
                }
          }
            if(breakInnerLoop)
            {
            continue
            }
        }

dviljoenの答えとの本質的な違いは何ですか?
Gert Arnold、

これは機能しません。外側のforループで "breakInnerLoop"条件をチェックしないので、次のループまで繰り返すだけです。また、jとJを記述し、セミコロンがないため、コンパイルされません。
セバスチャン

-4

私があなたがgotoステートメントを参照する人の答えを受け入れたのを見ると、現代のプログラミングと専門家の意見ではgotoはキラーです、私たちはそれをいくつかの特定の理由があるキラーと呼びました、ここではそれについては議論しませんこの時点で、しかしあなたの質問の解決策は非常に簡単です、私は私の例でそれを示すように、この種のシナリオでブールフラグを使用することができます:

            for (; j < 10; j++)
            {
                //solution
                bool breakme = false;
                for (int k = 1; k < 10; k++)
                {
                   //place the condition where you want to stop it
                    if ()
                    {
                        breakme = true;
                        break;
                    }
                }

                if(breakme)
                    break;
               }

シンプルでプレーン。:)


休憩を提案する前に質問を読んでください。したがって、反対票。
cmroanirgo 2016

1
今それを読んでください、しかし私がこの回答を投稿したとき、ブールを使用していないの編集されたバージョンは追加されませんでした、これが私がこの回答を投稿した理由です。
Steve

1
それは個人的なものではありません。残念ながら、投票は現在ロックされています;)トップへの最良の回答を得るためにSOの必要な部分です(これは常に発生するわけではありません)
cmroanirgo

-6

breakキーワードを見た?あー

これは単なる擬似コードですが、私が何を意味するかを確認できるはずです。

<?php
for(...) {
    while(...) {
        foreach(...) {
            break 3;
        }
    }
}

次のbreakような機能を考えている場合break()、そのパラメータは抜け出すループの数になります。ここのコードの3番目のループにいるので、3つすべてから抜け出すことができます。

マニュアル:http : //php.net/break


13
PHPの質問ではありません。
Zerga 2014年

-10

「ブール演算」を実行したくない場合は、実際にスローすることが唯一の解決策だと思います。あなたがしてはいけないことは明らかに..!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.