10

Can someone tell me how to break the main loop when I have nested loops?
Example*:

/*Main loop*/
for(int y = 0; y < 100; y+=10)
{
    /*Sub loop*/
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 60) 
        { 
            //Break the main loop 
        }
    }
}

*This code do nothing, it's just an example

What should I put in the place of the "Break main loop" comment? In java there are labels which I can break (when i set a label to the main loop named "MainLoop" I can write "break MainLoop;" and it will be valid), but what can I do here?

Thanks in advise!

Bankin
  • 777
  • 1
  • 16
  • 31

13 Answers13

19

goto!

I fail to understand this persistent meme which says that goto is considered "harmful". When used correctly, it is very powerful, and this is such a case.

fge
  • 119,121
  • 33
  • 254
  • 329
  • One day when someone hands you three decade-old FORTRAN code that was peppered with poorly written GOTOs, and tells you to fix the bugs, and you discover that it is _impossible_ to refactor, you will understand. The best programmers can do magic with GOTO. The worst can do great evil. – Caleb Hattingh Dec 13 '11 at 22:51
  • 1
    The best programmers can use `goto` without causing any grief whatsoever, and create the most efficient code in the process. – Matt Lacey Dec 13 '11 at 22:55
  • 1
    +1, breaking nested loops is one of the few (only?) acceptable uses of goto imo. Much, much cleaner than using a flag. – Adam Rackis Dec 13 '11 at 23:23
  • @cjrh And that's why he said _Well used, it is very powerful, and this is such a case._. Right tool for the right situation. – Rob Dec 13 '11 at 23:50
  • I just don't see why some people here would rather use a flag than a goto in this case. – bevacqua Jan 05 '12 at 01:30
11
  • refactor so you don't need to exit nested loops in this way.
    Using return is often possible by putting the loops into a seperate function.
  • use goto.
  • Use a flag (ugly)
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • 2
    No one should ever use `goto` in a high-level language. – Jon Egeland Dec 13 '11 at 22:43
  • 4
    IMO flag-break-checkflag-break is even uglier than goto. But of course refactoring is the preferred choice where possible. – CodesInChaos Dec 13 '11 at 22:44
  • 6
    `goto` is perfectly legitimate, and this is the best use for it, it's more efficient than any of the other options presented. No programmer should live by rules such as "never use `goto`", instead you should know **when** to use `goto`. – Matt Lacey Dec 13 '11 at 22:49
  • 2
    @IAbstract This is `exactly` the type of situation where `goto` is the best answer. Stop regurgitating the `never use goto` rubbish you've been taught. Use the right tool in the right situation. – Rob Dec 13 '11 at 23:49
  • @Rob: the correct answer is to refactor. I don't like the *flag-break-checkflag-break* option either ...and it's not about regurgitation, it's about correctness. :) – IAbstract Dec 14 '11 at 01:57
6

Use a flag to signal termination:

for(int y = 0; y < 100; y+=10)
{
     bool flag = false;
     for(int x = 0; x < 100; x += 10)
     {
        if (x == 56)
        {
           flag = true;
           break;
        }
     }

     if(flag) break;
}
Tudor
  • 61,523
  • 12
  • 102
  • 142
  • 1
    Thats a verbose way to do it. You can just check the flag in the `for` loop conditional. – Jon Egeland Dec 13 '11 at 22:44
  • Nice thing about this is that it is very easy to understand for other programmers: zero surprise factor. – Caleb Hattingh Dec 13 '11 at 22:44
  • @Jon, I don't think it's a clean style to have more than one condition inside a for. – Tudor Dec 13 '11 at 22:45
  • 2
    I prefer goto over this workaround. (Of course only if refactoring is no good choice) – CodesInChaos Dec 13 '11 at 22:47
  • @cjrh do you actually think so? I, for one, think goto is *much* more obvious here -- not to mention more efficient. – fge Dec 13 '11 at 22:47
  • @fge: tbh, when for-loops require termination earlier than their limits suggest, I suspect that that should be an _exceptional_ condition, if you catch my meaning. From that point of view, goto and exceptions do exactly the same thing. – Caleb Hattingh Dec 13 '11 at 22:57
  • It's done with flags like that in PASCAL .. I thought that c# may have something cleverer like Java did .. but I'll use this .. I tried the goto statement but it didn't work properly. – Bankin Dec 14 '11 at 23:56
6

Some people would shoot me for suggesting the use of the goto statement, but breaking out of multiple loops is one of the places it can be very useful (and efficient):

/*Main loop*/
for(int y = 0; y < 100; y+=10)
{
    /*Sub loop*/
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 56) 
        { 
            goto MainLoopDone;
        }
    }
}

MainLoopDone:
// carry on here
Matt Lacey
  • 8,227
  • 35
  • 58
  • 5
    They're terrible when used by young coders and result in spaghetti code. As a developer you should use the tools available to you, and goto is the most efficient way of getting out of several nested loops. – Matt Lacey Dec 13 '11 at 22:44
  • I agree with the prior about spaghetti code I always use break or return – MethodMan Dec 13 '11 at 22:45
  • 1
    +1 - I'm with you - this is one of the few places where goto makes things better, not worse. Restructuring to avoid the nested loops would be ideal, but if that's not an option, then `goto` away! – Adam Rackis Dec 13 '11 at 23:25
  • 1
    Hogan's simple solution of an extra boolean variable is nearly just as a efficient, and a lot more maintainable and clear to other programmers. – Brian Deragon Dec 13 '11 at 23:37
  • 1
    I don't see how it's more maintainable. If there were more loops involved you'd have to change more code, also this doesn't require an extra variable. – Matt Lacey Dec 13 '11 at 23:42
  • Can you elaborate a little? You made need to post an updated version of your code for us to see what's going on. – Matt Lacey Dec 15 '11 at 00:25
3

often its better to put this into a separate function and then do a 'return'

void loop_de_loop()
{
  for(int y = 0; y < 100; y+=10)
  {
      /*Sub loop*/
      for (int x = 0; x < 100; x += 10)
      {
          if(x == 56) 
          { 
              return;
          }
      }
  }
}
Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
  • In the real nested loops I'm calculating some thing. If I have to pass them to a method it'll be really ugly ! – Bankin Dec 14 '11 at 23:53
  • depends how you do it....often these things get messy because people have lots of variables and haven't encapsulated them into a struct. Ideally you end up with a lot of functions that work on a struct. ( simplified OO). – Keith Nicholas Dec 14 '11 at 23:57
2

I don't know if there's a way to break out of nested loops in C#, but allow me to suggest a workaround.

You could throw the main loop into a function and return out of that function. You can return false; to indicate a premature break and return true; to indicate that the loop went all the way through, if that matters.

Platinum Azure
  • 45,269
  • 12
  • 110
  • 134
2

Flags, as suggested in the comments, are probably the best method:

boolean someFlag = true;

for(int y = 0; i < 100 && someFlag; y += 10) {
  for(int x = 0; x < 100 && somFlag; x += 10) {
    if(x == 56)
      someFlag = false;
  }
}
Jon Egeland
  • 12,470
  • 8
  • 47
  • 62
  • It's only that short because there is no code after the inner loop and after the if. With that code you need to add two breaks and a check. – CodesInChaos Dec 13 '11 at 22:50
0

I used LINQ to gather the interesting objects first then performed the operations on the results of the LINQ query. Thereby removing nested loops and replacing with one loop.

flobadob
  • 2,804
  • 2
  • 22
  • 23
0
/*Main loop*/
for(int y = 0; y < 100; y+=10)
{
    bool makeMeBreak = false;

    /*Sub loop*/
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 56) 
        { 

            //Break the main loop 
            makeMeBreak = true;
            break;
        }
    }
    if (makeMeBreak) break;
}
Hogan
  • 69,564
  • 10
  • 76
  • 117
0

There's no good generic answer. The 'right way' depends on the real problem. The best way might be to put the outer loop in a function and then use return; to break out of it. It might be x=100; y=100;. It might be done=true;. Heck, it might even be goto (kidding).

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0

Not advisable but you can use goto. See this.

public class GotoTest1
{
    static void Main()
    {
        int x = 200, y = 4;
        int count = 0;
        string[,] array = new string[x, y];

        // Initialize the array:
        for (int i = 0; i < x; i++)

            for (int j = 0; j < y; j++)
                array[i, j] = (++count).ToString();

        // Read input:
        Console.Write("Enter the number to search for: ");

        // Input a string:
        string myNumber = Console.ReadLine();

        // Search:
        for (int i = 0; i < x; i++)
        {
            for (int j = 0; j < y; j++)
            {
                if (array[i, j].Equals(myNumber))
                {
                    goto Found;
                }
            }
        }

        Console.WriteLine("The number {0} was not found.", myNumber);
        goto Finish;

    Found:
        Console.WriteLine("The number {0} is found.", myNumber);

    Finish:
        Console.WriteLine("End of search.");


        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/*
Sample Input: 44

Sample Output
Enter the number to search for: 44
The number 44 is found.
End of search.
*/

Not advised because it makes the flow harder to understand. Other option of course is to set some flag in the inner loop and check it in the outer loop, I discounted that as it's obvious and assume you know it anyway.. :)

Kashyap
  • 15,354
  • 13
  • 64
  • 103
0

Since, as you've mentioned, there's no labels on the break command, you could do something like this:

/*Main loop*/
bool fFound;
for(int y = 0; y < 100 && !fFound; y+=10)
{
    /*Sub loop*/
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 56) 
        { 
            //Break the main loop 
            fFound = true;
            break; //Break inner loop
        }
    }
}
Mike Christensen
  • 88,082
  • 50
  • 208
  • 326
0

As others have said, the "correct" answer depends on the problem you're solving. If you can, breaking it into smaller pieces is the preferred route. Something along this model:

object MainLoop ()
{
    object result = null;
    for(int y = 0; y < 100; y+=10)
    {
        result = SubLoop(y);
        if (result != null)
        {
            break;
        }
    }
    return result;
}

object SubLoop (int y)
{
    object result = null;
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 56)
        {
            result = objectInstance;
            break;
        }
    }
    return result;
}

In my opinion, it's ugly to varying degrees to have multiple return statements from a single function, use extra flags, or (shudder) use goto's. But, sometimes one of those is necessary.

Edit: This is demonstrating using this method to return a useful object of some kind, you would have "Customer" or "IDataAccess" or "bool" or something other than "object" as the return types if using this for real.

That Chuck Guy
  • 443
  • 4
  • 12