235

別のループ内にネストされた for ループがある場合、両方のループ (内側と外側) からできるだけ早く効率的に抜け出すにはどうすればよいでしょうか?

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

これを行うための迅速で良い方法は何ですか?

例外は安くはない/真に例外的な状態でのみスローする必要があるなどと考えていました。したがって、このソリューションはパフォーマンスの観点からは良くないと思います。

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

4

25 に答える 25

234

しかし、gotoそれは醜く、常に可能であるとは限りません。ループをメソッド (または anon-method) に配置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");
于 2008-11-28T00:03:37.080 に答える
101

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と、外側のループの次の繰り返しに魔法のようにジャンプすることはありません。そのため、内側のループの外側にコードがある場合、このアプローチにはさらにチェックが必要です。そのような場合は、他の解決策を検討してください。

このアプローチはforwhileループでは機能しますが、 では機能しませんforeach。非表示の列挙子にコードでアクセスできない場合は、foreachそれを変更することはできIEnumeratorません (「MoveToEnd」メソッドがなくても)。

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

于 2008-11-28T02:21:38.097 に答える
31

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

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
}
于 2008-11-28T00:07:24.640 に答える
23

これについて私を引用しないでください。ただし、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 ) {}
于 2008-11-28T00:06:52.613 に答える
16

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

于 2008-11-28T00:04:43.083 に答える
12

あなたは、クイック、ナイス、ブール値の使用なし、goto の使用なし、および C# の組み合わせを要求しました。やりたいことを実行する可能性のあるすべての方法を除外しました。

goto を使用するのが、最も迅速で見苦しくない方法です。

于 2008-11-28T00:47:14.107 に答える
11

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

def do_until_equal():
  foreach a:
    foreach b:
      if a==b: return
于 2008-11-28T00:10:42.293 に答える
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
    ...

}
于 2008-12-20T17:48:03.613 に答える
2

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.
于 2008-11-28T05:22:43.020 に答える
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;
}

...私が好きな反後藤の「ファンボーイ」の助けになることを願っています:)

于 2013-06-20T01:03:06.700 に答える
0

return内側のループ内で使用するだけで、2 つのループが終了します...

于 2022-02-28T22:22:26.313 に答える
0

for ループの 2 番目のステートメント自体がブレーク条件であることを忘れがちなので、コード内に追加の if を含める必要はありません。

このようなものは動作します:

bool run = true;
int finalx = 0;
int finaly = 0;
for (int x = 0; x < 100 && run; x++)
{
    finalx = x;
    for (int y = 0; y < 100 && run; y++)
    {
        finaly = y;
        if (x == 10 && y == 50) { run = false; }
    }
}
Console.WriteLine("x: " + finalx + " y: " + finaly);  // outputs 'x: 10 y: 50'
于 2022-01-13T15:09:03.867 に答える
-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 
}
于 2014-09-10T14:03:03.457 に答える
-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
            }
        }
于 2012-08-10T12:25:34.873 に答える
-6

breakキーワードも見ましたか?うーん

これは単なる疑似コードですが、私の言いたいことがわかるはずです。

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

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

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

于 2013-12-14T01:26:29.673 に答える
-11

「ブール的なこと」をしたくない限り、唯一の解決策は実際にスローすることだと思います。これは明らかにすべきではありません..!

于 2008-11-28T00:02:30.310 に答える