Как завершить внешний цикл во вложенных циклах?
каков наилучший способ завершить все вложенные циклы в приведенном ниже примере. Как только утверждение if истинно, я хочу завершить внешнее утверждение for (с помощью I). Другими словами, Мне нужно остановить весь цикл. Есть ли лучший способ, чем установка I на 10?
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
break;
}
}
}
14 ответов
Я бы рефакторинг это метод, а просто называем return
когда мне нужно.
вы также можете использовать goto
, а я есть использовать goto
для этого, но это не одобряется. Что глупо; этот сценарий почему он существует в языке.
void DoSomeStuff()
{
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
return;
}
}
}
}
...somewhere else...
DoSomeStuff();
Не стреляйте в меня, но это может действительно гарантировать goto:
for (int I = 0; I < 10; I++) {
for (int A = 0; A < 10; A++) {
for (int B = 0; B < 10; B++) {
if (something)
goto endOfTheLine;
}
}
}
endOfTheLine:
Console.WriteLine("Pure evilness executed");
Если вы хотите выйти из все петли, вы можете переработать его в нечто немного более структурированным:
bool done = false;
for (int i = 0; i < 10 && !done; i++) {
for (int a = 0; a < 10 && !done; a++) {
for (int b = 0; b < 10 && !done; b++) {
if (something) {
done = true;
continue;
}
}
}
}
Если тела цикла не производят побочного эффекта, а просто ищут первое значение, где "что-то" истинно, то это исправит проблему, исключив все петли в первую очередь.
var query = from I in Enumerable.Range(0, 10)
from A in Enumerable.Range(0, 10)
from B in Enumerable.Range(0, 10)
where something(I, A, B)
select new { I, A, B };
var result = query.FirstOrDefault();
if (result == null)
{
Console.WriteLine("no result");
}
else
{
Console.WriteLine("The first result matching the predicate was {0} {1} {2},
result.I, result.A, result.B);
}
но не делайте этого, если циклы имеют побочные эффекты; запросы-действительно плохое место для побочных эффектов. Если внутренний цикл имеет побочный эффект, вы можете сделать что-то вроде этого:
var triples = from I in Enumerable.Range(0, 10)
from A in Enumerable.Range(0, 10)
from B in Enumerable.Range(0, 10)
select new { I, A, B };
foreach(var triple in triples)
{
if (something(triple.I, triple.A, triple.B))
break;
DoSomeSideEffect(triple.I, triple.A, triple.B);
}
и теперь есть только один цикл, чтобы вырваться из, не три.
почему бы не сделать:
for (int I = 0; I < 10 || !something; I++)
{
for (int A = 0; A < 10 || !something; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
{
I=10;
break;
}
}
}
}
вы всегда можете использовать тот факт, что в for
таким образом:
bool working = true;
for (int i=0; i<10 && working; i++)
{
for (int j=0; j<10 && working; j++)
{
for (int k=0; k<10 && working; k++)
{
Console.WriteLine(String.Format("i={0}, j={1}, k={2}", i,j,k));
if (i==5 && j==5 && k==5)
{
working = false;
}
}
}
}
Я бы склонялся в пользу goto
также еще вам придется выйти из каждого цикла:
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
break;
}
if (something)
break;
}
if (something)
break;
}
Если это конечная задача в методе, вы можете вернуться, когда условие истинно. в противном случае вы должны сделать все значения максимальными значениями
if (something)
{
I=10;
B=10;
A=10;
break;
}
for (int I = 0; I < 10; I++) {
for (int A = 0; A < 10; A++) {
for (int B = 0; B < 10; B++) {
if (something){
B=13;
A=13;
I=13;
}
}
}
}
очень примитивное решение.
простым решением является рефакторинг вложенных циклов в отдельный метод с соответствующим типом возврата, который вы хотели бы знать в этот момент:
в моем случае я предположу, что вы хотели значения I, A и B в этот момент, тривиальные с кортежем.
// original method
...
var x = FindFirst()
...
// separate method
public Tuple<int,int,int> FindFirst()
{
for (int I = 0; I < 10; I++)
{
for (int A = 0; A < 10; A++)
{
for (int B = 0; B < 10; B++)
{
if (something)
return Tuple.Create(I,A,B);
}
}
}
return null;
}
Если вам нужно передать в любом дополнительном состоянии методу (для границ или что-то бит), просто передайте их как параметры.
Если вы хотите справиться с неспособностью найти первый в другой манере, то что-то вроде
bool TryFindFirst(out Tuple<int,int,int> x)
будет другой.
в качестве примечания использование заглавных букв для имен переменных (особенно однобуквенных) считается плохим стилем в c# (и многих других языках)
Я не знаю, если C#
поддерживает его, но некоторые языки поддерживают:
break n;
здесь n
- количество вложенных циклов для разрыва.
вы всегда можете удовлетворить ожидания циклов:
Если (что-то) B = 10
изменить: (кажется, вы включили это в свой пост через редактирование)
Если вам не нравится, как это выглядит, вы можете обернуть функцию, такую как:
Удовлетворить(B, 10)
тогда выглядит чище, но на самом деле не нужен.
другая возможность-каскадировать проверку на isSomething во всех циклах. добавить
if (something)
break;
во всех 3 петли
лично я бы пошел с методом Paxdiablo выше (+1 для этого), но альтернатива ниже - это зависит от того, должен ли OP знать, что такое числа I, A и B, когда "что-то" верно, потому что iab были объявлены в цикле, я предполагаю, что нет.
bool done = false;
int i, a, b;
for (i = 0; i < 10 ; i++) {
for (a = 0; a < 10 ; a++) {
for (b = 0; b < 10 ; b++) {
if (something) {
done = true;
break;
}
}
if (done) break;
}
if (done) break;
}
// i, a and B are set to the last numbers where "something" was true