8

how to break first for each loop from second nested for each loop in c#,I want to check some conditions in the second for each loop then try to break the parent for each loop

foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
                break;//but want to break first foreach loop
          }
     }
}
Amit Kundu
  • 83
  • 1
  • 4

6 Answers6

9

Quick answer:

foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
                goto end; // I'd probably add a comment here
          }
     }
     // *1
}
end:
{} // the rest of your code.

But, but SESE...

SESE violations are violations of the Single Entry Single Exit principle. It's quite easy to fix, by using an extra condition:

bool found = false;
for (int i=0; i<foo.Count && !found; ++i)
{
    for (int j=0; j<bar.Count; ++j) 
    {
        if (...) { found = true; }
    }
    // *1 
    if (!found) { ... }
}

So why use a GOTO here?

I believe that creating proper, maintainable code means that you use the language constructs that most closely describes your intent. "Code" here is always composed of two things:

  • Control flow, which is expressed through things like for, while, break and goto.
  • Data flow, which is expressed through expressions, variables, and other memory access.

The intent of the OP is to break out of a nested loop, which is the equivalent of a control flow operation. I therefore believe you should use the control flow operation that most closely represents what the intent is - which is in this case a goto.

Note that this is not at all a reason you should abuse for introducing goto statements all over the place; if you do, the code will become very hard to read, which has nothing to do with maintainability and readability. You should consider the goto statement as a 'last resort control flow' statement, which is very rarely used in properly crafted code.

That said, in this case, this means that you shouldn't create local variables to handle control flow, unless that's absolutely necessary (e.g. if there's no language construct available that can express your intent clearly). For the same reason, I wouldn't have used Linq in this particular scenario.

I want performance. What should I do?

I believe most abuse of language constructs results from not understanding how the compiler deals with code, which is why I make it a habit of explaining parts of how it works internally. Please keep in mind that I recommend using a goto because it most clearly describes your intent, not because it might be a bit faster. Here goes:

Imagine being the compiler. You have a ton of code at the point of *1 in your code and cannot use return. Now there's two options:

  1. You can use a goto.
  2. You can use the extra flag.

Option 1 will compile to a field, which has memory. Memory is 'scarse' in the sense that compilers will do their best to consume as little memory as possible, preferable in registers. That's where your performance originates from. So, the compiler will attempt to eliminate the flag.

To do this, your compiler will do a ton of flow analysis and other stuff, in an attempt to determine that there are actually two code paths: the one is when the flag is set and the other one if it's not.

Now, if you're lucky the compiler will have its 'aha' moment and change your code from (2) to a simple GOTO, in which case the sky is still blue and everyone is happy.

However, if you're not lucky (and there are a ton of practical reasons for this to happen), it will not detect this from flow analysis and won't create the GOTO. Since your flag is used in the inner loop, it might even allocate a register for this, which might be the worst case scenario.

If you would have used the goto in the first place, there's no need for all this. You simply give the compiler the right solution. Simple.

Hrm do you have more details about how the compiler does this?

Yes, look at this 2 hour video of Chandler that explains a lot on how compilers work: https://www.youtube.com/watch?v=FnGCDLhaxKU

-updated- Apparently some people misintepreted my story as was pointed out by @Groo. I've made some adjustments to clarify what I meant to say.

atlaste
  • 30,418
  • 3
  • 57
  • 87
  • 5
    https://xkcd.com/292/ – Loofer Mar 02 '16 at 12:05
  • 1
    @Loofer: once in a blue moon, you let yourself use `goto`, especially if you can't put `return`. – Dmitry Bychenko Mar 02 '16 at 12:07
  • @Loofer Loops are compiled to IL GOTO's and LABEL's as well. Just don't make it a habit if you have an alternative. – atlaste Mar 02 '16 at 12:07
  • @DmitryBychenko Exactly. It makes little sense to use flags if you mean to use a goto IMHO. Added a bit of explanation about that. – atlaste Mar 02 '16 at 12:17
  • 1
    [To quote the man](http://c2.com/cgi/wiki?PrematureOptimization): *"Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a **strong negative impact when debugging and maintenance are considered**. We should **forget about small efficiencies**, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%."* – vgru Mar 02 '16 at 12:28
  • @Groo So let me get this straight: you argue that you prefer *more code*, that's *harder to optimize* and *arguably harder to read* while there are *perfectly good language constructs that exactly describe what you want* and *will be optimized* (just because you dislike `goto`)? This is not about _premature optimization_; that's just doesn't make any sense to me. – atlaste Mar 02 '16 at 13:47
  • That's a lot of claims, but let me try: 1) *you argue that you prefer more code, that's harder to optimize* - no, I prefer **readable and maintenable code**, even if it's **slightly** larger and **slightly** slower. Do you use `for` loops instead of `foreach` and `LINQ` all over your code?, 2) *arguably harder to read* - arguably. Many developers find LINQ unreadable, for example. 3) *perfectly good language constructs* - `goto` is a perfectly valid keyword, I agree, it's the pattern that is considered to be far from "perfectly good". – vgru Mar 03 '16 at 12:06
  • And finally 4) *this is not about premature optimization* - well, your answer is pretty much the longest in this thread, concentrating almost exclusively on compilers, flow analysis, CPU registers, concluding that one should *"simply give the compiler the right solution"*. You even added a link to a 2 hour video about compilers. – vgru Mar 03 '16 at 12:07
  • @Groo Sorry; I believe what I meant to explain and how it was percieved differs. I see your point, which was not my intent to express; I've changed some text to clarify. As to the details: (1) Of course, and no I do not. I use *the language constructs that most clearly describe my intent*. In this case the intent is to break out of a complex control flow, which the `goto` construct is uniquely capable of handling. (3) "Pattern" is a container word here. The pattern that you're describing is 'spaghetti code'; nothing do with this case. (4) I believe people should know what they're doing. – atlaste Mar 03 '16 at 13:10
5

You could do so by using a 'flag'

bool breakout = false
foreach(//do some stuff)
{
     foreach(//do some stuff)
     {
          if(//check some condition)
          {
             breakout = true;
             break;
          }
     }
     if(breakout)
      break;
}
Marcel B
  • 508
  • 2
  • 9
MX D
  • 2,453
  • 4
  • 35
  • 47
3

If you can't return, I suggest using Linq, it makes your code readable:

Boolean found = false;

foreach(var item1 in source1.TakeWhile(_ => !found)) {
     foreach(var item2 in source2.TakeWhile(_ => !found)) {
          if (some condition)
          {
               found = true;

               //break; // Not necessary
          }
     }
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
1
bool doBreak = false;
foreach(//do some stuff)
{
    foreach(//do some stuff)
    {
        doBreak = <check some condition>;
        if(doBreak) break;
    }
    if(doBreak) break;
}
1

You can try to use return like this:

foreach(//do some stuff)
    foreach(//do some stuff)
       if(//check some condition)
          return;
Rahul Tripathi
  • 168,305
  • 31
  • 280
  • 331
  • 7
    While this may serve the purposes of the OP, `return` does more than break out of the loops - it breaks out of the function that contains the loops! And in fairness to others suggesting answers, nowhere does OP mention that these loops are part of a function that returns the value they were looping to get. – rskar Mar 02 '16 at 12:41
1

You can use WHILE. Maybe this code helps to you

foreach(// Some condition here)
{
    //solution
    bool breakme = false;

    while (// Some condition here)
    {
        foreach (// Some condition here)
        {
            if (// Condition again)
            {
                //Do some code
            }
            if (// Condition again)
            {
                //Stop the first foreach then go back to first foreach
                breakme = true;
                break;
            }
        }
    }
    if(breakme)
    {
        break;
    }
}
ibrahim
  • 63
  • 6