Убегая из вложенного цикла

202
задан Bill the Lizard 27 August 2011 в 16:20
поделиться

11 ответов

Ну, 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");
195
ответ дан Marc Gravell 23 November 2019 в 05:00
поделиться

Я думаю, если Вы не хотите сделать, "булева вещь" единственное решение состоит в том, чтобы на самом деле бросить. Который Вы, очевидно, не должны делать..!

-9
ответ дан Thomas Hansen 23 November 2019 в 05:00
поделиться

Так как я увидел в первый раз 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.
1
ответ дан Jesse C. Slicer 23 November 2019 в 05:00
поделиться

Я видел много примеров, которые используют "повреждение", но ни один, что "продолжает" использование.

Это все еще потребовало бы какого-то флага во внутреннем цикле:

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
    ...

}
2
ответ дан dviljoen 23 November 2019 в 05:00
поделиться

Вы попросили комбинацию быстрых, хороших, нет смысла в булевской переменной, нет смысла goto, и C#. Вы исключили все возможные способы сделать то, что Вы хотите.

самый быстрый и наименее ужасный путь состоит в том, чтобы использовать goto.

9
ответ дан Windows programmer 23 November 2019 в 05:00
поделиться

фактор в функцию/метод и использует ранний возврат или перестраивает Ваши циклы в выражение while. goto/exceptions/whatever являются, конечно, не соответствующими здесь.

def do_until_equal():
  foreach a:
    foreach b:
      if a==b: return
11
ответ дан Dustin Getz 23 November 2019 в 05:00
поделиться

Действительно ли возможно осуществить рефакторинг вложенный для цикла в закрытый метод? Тем путем Вы могли просто 'возвратиться' из метода для выхода из цикла.

15
ответ дан NoizWaves 23 November 2019 в 05:00
поделиться

Не заключайте мне в кавычки на этом, но Вы могли использовать 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 ) {}
19
ответ дан BritishDeveloper 23 November 2019 в 05:00
поделиться

Используйте подходящую защиту во внешнем цикле. Установите защиту во внутреннем цикле перед повреждением.

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
}
26
ответ дан tvanfosson 23 November 2019 в 05:00
поделиться

Это решение не относится к C#

За людей, которые нашли этот вопрос через другие языки, JavaScript, Java, и D позволяет маркированные повреждения и продолжается :

outer: while(fn1())
{
   while(fn2())
   {
     if(fn3()) continue outer;
     if(fn4()) break outer;
   }
}
40
ответ дан Luis Perez 23 November 2019 в 05:00
поделиться

Адаптация C# подхода часто использовала в C - установленное значение переменной внешнего цикла за пределами условий цикла (т.е. для цикла с помощью международной переменной 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, волшебно не перейдет к следующему повторению внешнего цикла - поэтому, если у Вас будет код за пределами внутреннего цикла, этот подход требует большего количества проверок. Рассмотрите другие решения в таком случае.

Этот подход работает с for и while циклы, но не работает на foreach. В случае foreach у Вас не будет доступа кода к скрытому перечислителю, таким образом, Вы не сможете изменить его (и даже если Вы могли IEnumerator не иметь некоторого метода "MoveToEnd").

Список благодарностей авторам встроенных комментариев:
i = INT_MAX - 1 предложение [1 112] Meta
for / foreach комментарий [1 113] ygoe
.
Надлежащий IntMax [1 114] комментарий jmbpiano

о коде после внутреннего цикла [1 115] blizpasta

93
ответ дан Alexei Levenkov 23 November 2019 в 05:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: