247

If I have a for loop which is nested within another, how can I efficiently come out of both loops (inner and outer) in the quickest possible way?

I don't want to have to use a boolean and then have to say go to another method, but rather just to execute the first line of code after the outer loop.

What is a quick and nice way of going about this?

I was thinking that exceptions aren't cheap/should only be thrown in a truly exceptional condition etc. Hence I don't think this solution would be good from a performance perspective.

I don't feel it it is right to take advantage of the newer features in .NET (anon methods) to do something which is pretty fundamental.

TylerH
  • 20,799
  • 66
  • 75
  • 101
GurdeepS
  • 65,107
  • 109
  • 251
  • 387

26 Answers26

255

Well, goto, but that is ugly, and not always possible. You can also place the loops into a method (or an anon-method) and use return to exit back to the main code.

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

vs:

// 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");

Note that in C# 7 we should get "local functions", which (syntax tbd etc) means it should work something like:

// 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");
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 67
    In this type of situation I don't think using goto is any worse than the normal use of something like break (after all they're both just unconditional branches to a label, it's just that with break the label is implicit). – Greg Beech Nov 28 '08 at 00:07
  • 51
    sometimes goto is less evil than the alternatives – seanb Nov 28 '08 at 00:23
  • 3
    Er, how is goto less evil than the other alternative he mentions, a plain return statement? Don't we like functions now? It's been a few decades since we wrote everything in big huge chunk of code. Today, we have these things called "functions", which means you don't need to use goto. Try them. – jalf Dec 20 '08 at 16:02
  • Why use goto when you can use break? – Oliver Friedrich Dec 20 '08 at 16:28
  • 7
    @BeowulfOF - break will only break out of the inner loop, not the inner and outer loops. – Greg Beech Feb 02 '09 at 21:54
  • 52
    Goto itself isn't ugly. What is ugly is abusing goto which results in spaghetti code. Using goto to break out of nested loop is perfectyly ok. Besides, note that all break, continue and return, from structural programming point of view, are hardly better than goto - basically they're the same thing, just in nicer packaging. That's why pure structural languages (such as original Pascal) lack all of three. – el.pescado - нет войне Apr 04 '10 at 15:28
  • 7
    The only problem with goto is that once you put that label there. There's a possibility that by mistake statement gets inserted between goto and end of loop making the break code skip that statement also. Java for example prevents this by allowing labels only to label ends of loops. – Ivan May 19 '11 at 11:11
  • 19
    @el.pescado is totally right: many coders have been mislead to believe `goto` is harmful *per-se*, while it simply is the **correct** instrument to do some things, and like many instruments may be misused. This religious aversion against `goto` is frankly quite stupid and *definitely* un-scientific. – o0'. Jan 17 '12 at 13:42
  • 12
    It seems bizarre that C# has a `goto` but it doesn't have a labelled `break` or `continue` in the way other languages do. In light of this language restriction I think `goto` is exactly the right solution to this problem. – nnnnnn Jan 26 '12 at 05:46
  • 2
    Functions are OK but Dijkstra also said multiple returns/exits are spaghetti. – QuentinUK Mar 02 '16 at 12:53
  • 5
    @SinanILYAS rote rules like "never use goto" is the only "rookie" thing; having a default of "avoid goto" is fine - I can respect that - but: if you don't understand the what and the why, *anything* can be bad guidance. If you understand what you're avoiding and why, you can understand when the guidance does and doesn't apply, even if the "does" is 99% of the time. For a different example, "all `struct` should be either `readonly struct` or - much more rarely (and with a reason) - `ref struct`" is a great piece of guidance for rookies, but the reality gets much more interesting than that. – Marc Gravell May 14 '19 at 07:20
  • The local functions of C# 7 sound extremly interesting, I like it! Seems promissing to turn C# into a more versatile and fluent language – Florian Wolf Feb 08 '21 at 18:07
  • I agree with @GregBeech that this is a classic case for using goto – Assaf S. Oct 11 '21 at 13:48
  • 1
    I love the comments supporting the use of goto. Everything in programming has its use cases, no matter how niche they might be. People who say "NEVER use this/that in programming" usually don't fully understand what they're talking about imo. – Nyde Oct 17 '22 at 18:05
104

C# adaptation of approach often used in C - set value of outer loop's variable outside of loop conditions (i.e. for loop using int variable INT_MAX -1 is often good choice):

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    
}

As note in code says break will not magically jump to next iteration of the outer loop - so if you have code outside of inner loop this approach requires more checks. Consider other solutions in such case.

This approach works with for and while loops but does not work for foreach. In case of foreach you won't have code access to the hidden enumerator so you can't change it (and even if you could IEnumerator doesn't have some "MoveToEnd" method).

Acknowledgments to inlined comments' authors:
i = INT_MAX - 1 suggestion by Meta
for/foreach comment by ygoe.
Proper IntMax by jmbpiano
remark about code after inner loop by blizpasta

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Nils Pipenbrinck
  • 83,631
  • 31
  • 151
  • 221
  • @DrG: Won't work in c# as "The break statement terminates the closest enclosing loop or switch statement in which it appears." (msdn) – blizpasta Mar 14 '11 at 05:29
  • 1
    @blizpasta So? If he makes the condition on the outer loop false (like he did), it will exit both. – Patrick Mar 23 '11 at 01:23
  • @Patrick I was wrong. Thanks. It'll work for nested loops with no statements after the inner loops. – blizpasta Mar 23 '11 at 02:05
  • 54
    you should use i = INT_MAX - 1; otherwise i++ == INT_MIN < 100 and loop will continue – Meta May 04 '11 at 11:04
  • 4
    @ktutnik It won't work with foreach because you won't have code access to the hidden enumerator. Also IEnumerator doesn't have some "MoveToEnd" method. – ygoe Jun 27 '14 at 08:30
  • Minor nitpick on an old and decent answer... But, by itself, this code won't compile in C#. The language does not have an `INT_MAX` constant. The C# equivalent is `int.MaxValue`. – jmbpiano May 28 '17 at 15:42
  • Accidentally set i to `Int32.MaxValue` instead of `Int32.MaxValue - 1` and see how long it takes you debug it, especially if the loop happens to be in an `unchecked` block. Any bets? – Suncat2000 Mar 12 '20 at 18:47
  • Oh yes, this option is much better than using exit_condition in the loop exit condition.... – Trap May 16 '20 at 14:47
  • *nerd-mode on* The outer-loop will check the condition again and jumps after the check. One instruction more or less is not important, but it is not quickest way. *nerd-mode off* – akop Jun 03 '20 at 10:20
47

This solution does not apply to C#

For people who found this question via other languages, Javascript, Java, and D allows labeled breaks and continues:

outer: while(fn1())
{
   while(fn2())
   {
     if(fn3()) continue outer;
     if(fn4()) break outer;
   }
}
Luis Perez
  • 27,650
  • 10
  • 79
  • 80
BCS
  • 75,627
  • 68
  • 187
  • 294
  • 47
    its sad this can not been done with c#, it would in so many times produce cleaner code. – Rickard May 11 '12 at 20:39
  • 22
    I actually became excited for a second until I realized this was NOT for c#. :( – Arvo Bowen Jul 22 '13 at 21:36
  • 1
    This concept is also for **PowerShell** in case somebody comes across the problem there. (They just put the colon in front of the label name.) Now I know this isn't PowerShell-specific... This syntax would be incompatible with the goto labels available in C#. PHP uses something else: break 3; Put the number of levels after the break statement. – ygoe Jun 27 '14 at 08:33
  • 2
    This is java not c# – Luca Ziegler Feb 07 '17 at 13:48
  • For those who would like to see this feature in C#, place your kudos here, please https://github.com/dotnet/csharplang/issues/869#issuecomment-326606003 – m93a Nov 30 '17 at 08:53
  • I've only "wanted" this .. once or twice in the last 4 years of 9-to-5 C# development. Most cases can be expressed in a cleaner form, with the few exceptions being some tight-loops-and-arrays. – user2864740 Jan 06 '20 at 18:38
31

Use a suitable guard in the outer loop. Set the guard in the inner loop before you break.

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

Or better yet, abstract the inner loop into a method and exit the outer loop when it returns false.

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

    .... some outer loop stuff

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

    ... more outer loop stuff
}
tvanfosson
  • 524,688
  • 99
  • 697
  • 795
24

Don't quote me on this, but you could use goto as suggested in the MSDN. There are other solutions, as including a flag that is checked in each iteration of both loops. Finally you could use an exception as a really heavyweight solution to your problem.

GOTO:

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

Condition:

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

Exception:

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 ) {}
Jan
  • 55
  • 2
  • 11
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 3
    these are all hacky workarounds where it would be super clean to just factor into a method and use early return – Dustin Getz Nov 28 '08 at 00:09
  • 4
    :) right, that is a simple solution, but you will have to pass all required local data into the method as arguments... This is one of the few places where goto might be the appropriate solution – David Rodríguez - dribeas Nov 28 '08 at 00:17
  • The Condition method doesn't even work because "more code" will be executed one time after exiting the inner loop before exiting the outer loop. The GOTO method works but does exactly what the poster said they don't want to do. The Exception method works but is uglier and slower than GOTO. – Windows programmer Nov 28 '08 at 00:43
  • I would highlight that semicolon after the label. This way that label can be even at the end of a block. +1 – Tamas Hegedus Jan 04 '16 at 00:28
  • 2
    @Windowsprogrammer The OP asked, "What is a quick and nice way of going about this?" Goto is the preferred solution: clean and concise, without involving a separate method. – Suncat2000 Mar 12 '20 at 18:52
18

Refactor the nested for loop into a private method. That way you could simply 'return' out of the method to exit the loop.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
NoizWaves
  • 2,650
  • 6
  • 28
  • 32
14

It seems to me like people dislike a goto statement a lot, so I felt the need to straighten this out a bit.

I believe the 'emotions' people have about goto eventually boil down to understanding of code and (misconceptions) about possible performance implications. Before answering the question, I will therefore first go into some of the details on how it's compiled.

As we all know, C# is compiled to IL, which is then compiled to assembler using an SSA compiler. I'll give a bit of insights into how this all works, and then try to answer the question itself.

From C# to IL

First we need a piece of C# code. Let's start simple:

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

I'll do this step by step to give you a good idea of what happens under the hood.

First translation: from foreach to the equivalent for loop (Note: I'm using an array here, because I don't want to get into details of IDisposable -- in which case I'd also have to use an IEnumerable):

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

Second translation: the for and break is translated into an easier equivalent:

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

And third translation (this is the equivalent of the IL code): we change break and while into a branch:

    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; 

While the compiler does these things in a single step, it gives you insight into the process. The IL code that evolves from the C# program is the literal translation of the last C# code. You can see for yourself here: https://dotnetfiddle.net/QaiLRz (click 'view IL')

Now, one thing you have observed here is that during the process, the code becomes more complex. The easiest way to observe this is by the fact that we needed more and more code to ackomplish the same thing. You might also argue that foreach, for, while and break are actually short-hands for goto, which is partly true.

From IL to Assembler

The .NET JIT compiler is an SSA compiler. I won't go into all the details of SSA form here and how to create an optimizing compiler, it's just too much, but can give a basic understanding about what will happen. For a deeper understanding, it's best to start reading up on optimizing compilers (I do like this book for a brief introduction: http://ssabook.gforge.inria.fr/latest/book.pdf ) and LLVM (llvm.org).

Every optimizing compiler relies on the fact that code is easy and follows predictable patterns. In the case of FOR loops, we use graph theory to analyze branches, and then optimize things like cycli in our branches (e.g. branches backwards).

However, we now have forward branches to implement our loops. As you might have guessed, this is actually one of the first steps the JIT is going to fix, like this:

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

As you can see, we now have a backward branch, which is our little loop. The only thing that's still nasty here is the branch that we ended up with due to our break statement. In some cases, we can move this in the same way, but in others it's there to stay.

So why does the compiler do this? Well, if we can unroll the loop, we might be able to vectorize it. We might even be able to proof that there's just constants being added, which means our whole loop could vanish into thin air. To summarize: by making the patterns predictable (by making the branches predictable), we can proof that certain conditions hold in our loop, which means we can do magic during the JIT optimization.

However, branches tend to break those nice predictable patterns, which is something optimizers therefore kind-a dislike. Break, continue, goto - they all intend to break these predictable patterns- and are therefore not really 'nice'.

You should also realize at this point that a simple foreach is more predictable then a bunch of goto statements that go all over the place. In terms of (1) readability and (2) from an optimizer perspective, it's both the better solution.

Another thing worth mentioning is that it's very relevant for optimizing compilers to assign registers to variables (a process called register allocation). As you might know, there's only a finite number of registers in your CPU and they are by far the fastest pieces of memory in your hardware. Variables used in code that's in the inner-most loop, are more likely to get a register assigned, while variables outside of your loop are less important (because this code is probably hit less).

Help, too much complexity... what should I do?

The bottom line is that you should always use the language constructs you have at your disposal, which will usually (implictly) build predictable patterns for your compiler. Try to avoid strange branches if possible (specifically: break, continue, goto or a return in the middle of nothing).

The good news here is that these predictable patterns are both easy to read (for humans) and easy to spot (for compilers).

One of those patterns is called SESE, which stands for Single Entry Single Exit.

And now we get to the real question.

Imagine that you have something like this:

// a is a variable.

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

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

The easiest way to make this a predictable pattern is to simply eliminate the if completely:

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

In other cases you can also split the method into 2 methods:

// 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;
}

Temporary variables? Good, bad or ugly?

You might even decide to return a boolean from within the loop (but I personally prefer the SESE form because that's how the compiler will see it and I think it's cleaner to read).

Some people think it's cleaner to use a temporary variable, and propose a solution like this:

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

I personally am opposed to this approach. Look again on how the code is compiled. Now think about what this will do with these nice, predictable patterns. Get the picture?

Right, let me spell it out. What will happen is that:

  • The compiler will write out everything as branches.
  • As an optimization step, the compiler will do data flow analysis in an attempt to remove the strange more variable that only happens to be used in control flow.
  • If succesful, the variable more will be eliminated from the program, and only branches remain. These branches will be optimized, so you will get only a single branch out of the inner loop.
  • If unsuccesful, the variable more is definitely used in the inner-most loop, so if the compiler won't optimize it away, it has a high chance to be allocated to a register (which eats up valuable register memory).

So, to summarize: the optimizer in your compiler will go into a hell of a lot of trouble to figure out that more is only used for the control flow, and in the best case scenario will translate it to a single branch outside of the outer for loop.

In other words, the best case scenario is that it will end up with the equivalent of this:

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:

// ...

My personal opinion on this is quite simple: if this is what we intended all along, let's make the world easier for both the compiler and readability, and write that right away.

tl;dr:

Bottom line:

  • Use a simple condition in your for loop if possible. Stick to the high-level language constructs you have at your disposal as much as possible.
  • If everything fails and you're left with either goto or bool more, prefer the former.
atlaste
  • 30,418
  • 3
  • 57
  • 87
  • OTOH: I only rarely have the desire to break outer loops or wish for goto-equiv (and lots of code that does could arguably be written more cleanly), although such might be more common in other domains .. today was such a case, but that was largely due to `yield return`. That is, while it's easy to show there are some useful cases, for most "application-level" code it's probably a very low occurrence of frustration with C#, excluding those "just coming from" C/C++ ;-) I also occasionally miss Ruby's "throw" (non-Exception unwinding) on occasion as it also fits in this domain. – user2864740 Nov 14 '17 at 00:28
  • 1
    @Suncat2000 Just introducing more code like variables and conditional branches to avoid using a `goto`, doesn't make your code more readable - I'd argue what happens is the exact opposite: in fact your control flow will contain more nodes - which is pretty much the definition of complexity. Just avoiding it to aid self-discipline sounds counter productive in terms of readability. – atlaste Mar 17 '20 at 12:44
  • @atlaste: Sorry, let me state my comment more clearly. What I should have said was: Nice explanation. But people avoiding goto isn't about performance; it's about avoiding abuse that causes lack of readability. We can assume the people who avoid `goto` just don't have the discipline to not abuse it. – Suncat2000 Mar 18 '20 at 13:38
  • @atlaste, what language is "ackomplish"? – Pacerier Apr 15 '20 at 22:06
  • To me the reason that Goto's seem to be bad is because unlike all other code, it takes us forward in time, to a place that we haven't read to yet, A magical place that we likely know nothing about yet. In other languages like powershell they have for/while labels so that you can break out of a specific loop that you have already entered. Goto's go against everything that modern languages set out to achieve. Honestly if they were ok to use then why not write our code like this. { ... } if ( ... )? I think we all understand why we don't do that – Alfredo Awesome Monazite Oct 13 '20 at 09:06
  • @AlfredoAwesomeMonazite In time? Huh? I think I understand what you mean, so I'm just going to give a few examples why that line of argument is flawed in many ways. (1) `do { ... } while (...); /* construct you describe */`. (2) `if (...) { ...} /* code follows which is the same as the goto construction */` (3) `start: [blah] goto start; /* moves back */`. (4) `throw [exception]; // unlike all other code...` (5) `while (...) { ... break; /* takes us forward 'in time' whatever that means */ }`. – atlaste Oct 13 '20 at 11:45
  • @atlaste "forward in time" meant: "To a part of the code that we haven't read yet" or "further than the next thing top down". Typically you explain what is about to happen: **if** (...) {...} || **do** {...} while (...) || **throw** [exception]. in terms of `break` you are going back to the start of the statement you are breaking and then breaking out, none of these can take you forward or to a completely random part of the code. Code in a function should read and execute down the page but a GoTo allows this to be broken which leads to bad practices and bad practices – Alfredo Awesome Monazite Feb 08 '21 at 03:08
  • @AlfredoAwesomeMonazite That line of argument makes no sense to me. Goto's are scoped, random goto's are not allowed. To take your own example of `break`, a goto goes back to the start of the scope ("statement" is wrong, you probably meant "scope"), and then finds the label. Compilers generally forbid random goto's, for various reasons such as uninitialized variables. Most practical use cases actually go back, because it can't be described cleanly with loops; an example is the round-robin case of hash tables. Exception handling is no different. – atlaste Feb 15 '21 at 14:49
13

You asked for a combination of quick, nice, no use of a boolean, no use of goto, and C#. You've ruled out all possible ways of doing what you want.

The most quick and least ugly way is to use a goto.

Windows programmer
  • 7,871
  • 1
  • 22
  • 23
  • 1
    Totally agree. Introducing a new method just to get rid of a single goto is silly. If the compiler can't inline that method call for whatever reason - we will end up with completely unnecessary overhead of an extra method call. Throwing and catching exceptions just to break the loop is both more verbose and ridiculously more expensive. – Zar Shardan Jun 06 '19 at 11:41
  • @Windowsprogramm: OP didn't ask for "no use of goto". He didn't want to "go to another method". The question was far from ruling out _all_ possible ways, but you're right to imply that goto is best here. – Suncat2000 Mar 12 '20 at 19:00
  • We all know that that jumping around wildly with `goto` is evil. But this is one of the rare cases where the use of `goto` is legitimate. It has been added to the language for some reason, hasn't it? – Olivier Jacot-Descombes Aug 23 '22 at 14:03
11

factor into a function/method and use early return, or rearrange your loops into a while-clause. goto/exceptions/whatever are certainly not appropriate here.

def do_until_equal():
  foreach a:
    foreach b:
      if a==b: return
Dustin Getz
  • 21,282
  • 15
  • 82
  • 131
7

The cleanest, shortest, and most reusable way is a self invoked anonymous function:

  • no goto
  • no label
  • no temporary variable
  • no named function

One line shorter than the top answer with anonymous method.

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");
Community
  • 1
  • 1
  • I've used this for other unrelated things but never like this. I found this simple way to implement what I needed. Thanks for the contribution. – Gary Smith Mar 30 '23 at 22:24
5

Sometimes nice to abstract the code into it's own function and than use an early return - early returns are evil though : )

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;
            }
        }
    }
}
Sky
  • 86
  • 1
  • 2
2

Since I first saw break in C a couple of decades back, this problem has vexed me. I was hoping some language enhancement would have an extension to break which would work thus:

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.
Jesse C. Slicer
  • 19,901
  • 3
  • 68
  • 87
2

I've seen a lot of examples that use "break" but none that use "continue".

It still would require a flag of some sort in the inner loop:

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

}
dviljoen
  • 1,612
  • 1
  • 16
  • 28
1

The easiest way to end a double loop would be directly ending the first loop

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
        }
    }
}
Kyle
  • 19
  • 1
  • 1
    This does not work as by using break you will end the inner loop. The outer loop will continue to iterate. – Alex Leo Jan 30 '20 at 06:55
1

Loops can be broken using custom conditions in the loop, allowing as to have clean code.

    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;   

With this code we ontain the following output:

  • External loop iteration 0
  • Inner loop iteration 0
  • Inner loop iteration 1
  • Inner loop iteration 2
  • Inner loop iteration 3
  • Inner loop iteration 4
  • The code after the inner loop will be executed when breaks
0

I remember from my student days that it was said it's mathematically provable that you can do anything in code without a goto (i.e. there is no situation where goto is the only answer). So, I never use goto's (just my personal preference, not suggesting that i'm right or wrong)

Anyways, to break out of nested loops I do something like this:

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;
}

... i hope that helps for those who like me are anti-goto "fanboys" :)

Tom
  • 4,096
  • 2
  • 24
  • 38
MG123
  • 402
  • 2
  • 14
  • Sorry to tell you, but your lecturer is the one to blame for your condition. If he'd bothered to force you to learn assembly, then you know that 'goto' is just a jump (of course I'm ignoring the fact that this is a c# question). – cmroanirgo Dec 28 '16 at 09:04
  • I gotta say, Given that pretty much all code is written in a way where you specify what your doing first (e.g. if ( ) {} instead of {} if ( ) and reading down the page in order) because it's easier to see what's happening, Goto's seem to contradict basically everything that stands for. I honestly wish they'd add labelled for's and while's since it comes before the "break" so you know what your breaking out of rather than travelling to some magic point in the future that the developer doesn't know about yet – Alfredo Awesome Monazite Oct 13 '20 at 08:52
0

That's how I did it. Still a workaround.

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

Another option which is not mentioned here which is both clean and does not rely on newer .NET features is to consolidate the double loop into a single loop over the product. Then inside the loop the values of the counters can be calculated using simple math:

int n; //set to max of first loop
int m; //set to max of second loop

for (int k = 0; k < n * m; k++)
{
    //calculate the values of i and j as if there was a double loop
    int i = k / m;
    int j = k % m;
    
    if(exitCondition)
    {
        break;
    }
}
Jeroen
  • 3,443
  • 2
  • 13
  • 15
0

People often forget that the 2nd statement of the for loops themselves are the break conditions, so there is no need to have additional ifs within the code.

Something like this works:

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'
fmigneault
  • 341
  • 3
  • 5
0

just use return inside the inner loop and the two loops will be exited...

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
0

I would just set a flag.

var breakOuterLoop = false;
for (int i = 0; i < 30; i++)
{
    for (int j = 0; j < 30; j++)
    {
        if (condition)
        {
            breakOuterLoop = true;
            break;
        }
    }
    if (breakOuterLoop){
        break;
    }
}
tdahman1325
  • 210
  • 3
  • 6
-3

Throw a custom exception which goes out outter loop.

It works for for,foreach or while or any kind of loop and any language that uses try catch exception block

try 
{
   foreach (object o in list)
   {
      foreach (object another in otherList)
      {
         // ... some stuff here
         if (condition)
         {
            throw new CustomExcpetion();
         }
      }
   }
}
catch (CustomException)
{
   // log 
}
Moesio
  • 3,100
  • 1
  • 27
  • 36
-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
            }
        }
  • What's the essential difference with dviljoen's answer? – Gert Arnold Aug 10 '12 at 12:50
  • That will not work, because you do not check the "breakInnerLoop" condition in the outer for loop, so you just iterate to the next loop, also you wrote j and J, and missed a semicolon, that will not compile. – Sebastian Apr 28 '16 at 13:42
-4

As i see you accepted the answer in which the person refers you goto statement, where in modern programming and in expert opinion goto is a killer, we called it a killer in programming which have some certain reasons, which i will not discuss it over here at this point, but the solution of your question is very simple, you can use a Boolean flag in this kind of scenario like i will demonstrate it in my example:

            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;
               }

simple and plain. :)

Steve
  • 1,022
  • 2
  • 9
  • 30
  • read the question before suggesting a break. Hence the downvotes. – cmroanirgo Dec 28 '16 at 09:21
  • 2
    read it now, but when i posted this answer the edited version of not using boolean was not added this is why i posted this answer.. but thanks for downvote! – Steve Jan 05 '17 at 19:04
  • 1
    It's not a personal thing. Unfortunately, the vote is now locked in ;) It's a necessary part of SO to get the best answers to the top (which doesn't always happen) – cmroanirgo Jan 05 '17 at 22:38
-6

Did you even look at the break keyword? O.o

This is just pseudo-code, but you should be able to see what I mean:

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

If you think about break being a function like break(), then it's parameter would be the number of loops to break out of. As we are in the third loop in the code here, we can break out of all three.

Manual: http://php.net/break

Ingwie Phoenix
  • 2,703
  • 2
  • 24
  • 33
-11

I think unless you want to do the "boolean thing" the only solution is actually to throw. Which you obviously shouldn't do..!

Thomas Hansen
  • 5,523
  • 1
  • 23
  • 28