Mirial
Mirial

Reputation: 247

How to terminate outer loop in nested loops?

What is the best way to terminate all nested loops in the example below. Once the if statement is true, I want to terminate the outer for statement (with I). In the other words I need the whole loop to stop. Is there better way than setting I to 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;
        }
    }
}

Upvotes: 14

Views: 2884

Answers (14)

chrisaut
chrisaut

Reputation: 1086

Don't shoot me, but this might actually warrant a 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");

Upvotes: 15

paxdiablo
paxdiablo

Reputation: 881173

Assuming you want to exit from all loops, you can refactor it into something a little more structured:

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

Upvotes: 14

JD Isaacks
JD Isaacks

Reputation: 57974

I don't know if C# supports it but some languages support:

break n;

Where n is the number of nested loops to break.

Upvotes: 2

ShuggyCoUk
ShuggyCoUk

Reputation: 36438

simple solution is to refactor the nested loops into a separate method with the relevant return type being whatever you wanted to know at that point:

in my case I will assume you wanted the the values of I, A and B at that point, trivial with a Tuple instead.

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

If you need to pass in any additional state to the method (for the bounds, or the something bit) just pass them as parameters.

If you wanted to handle failing to find the first one in a different fashion then something like

bool TryFindFirst(out Tuple<int,int,int> x) 

would be an alternate.

As a side note using capital letters for variable names (especially single letter ones) is considered poor style in c# (and many other languages)

Upvotes: 2

Eric Lippert
Eric Lippert

Reputation: 659984

If the loop bodies do not produce a side effect but rather merely are looking for the first value where "something" is true then would fix the problem by eliminating all the loops in the first place.

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

But don't do this if the loops have side effects; queries are a really bad place to put side effects. If the inner loop has a side effect then you can do something like this:

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

and now there is only one loop to break out of, not three.

Upvotes: 10

Bastardo
Bastardo

Reputation: 4152

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

A very primitive solution.

Upvotes: 2

Harag
Harag

Reputation: 1582

Personally I would go with Paxdiablo's method above (+1 for that), but an alternative is below - it depends if the OP needs to know what the I, A and B numbers are when "something" is true, be because iab were declared in the loop I'm guessing not.

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

Upvotes: 1

Lazarus
Lazarus

Reputation: 43064

You could always exploit the fact that there is a conditional statement in the for thus:

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

Upvotes: 3

Umesh CHILAKA
Umesh CHILAKA

Reputation: 1466

If this is the final task in method then you can return when condition is true. otherwise you have to make all the values to max values

if (something)              
    {
        I=10;   
        B=10;
        A=10;
        break;
    }

Upvotes: 2

fixagon
fixagon

Reputation: 5566

the other possibility is to cascade the check on isSomething in all for loops. you add the

if (something)                         
   break; 

in all 3 loops

Upvotes: 1

Eben Roux
Eben Roux

Reputation: 13246

I would lean in favour of goto also else you are going to have to exit each loop:

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

Upvotes: 2

Yuck
Yuck

Reputation: 50825

Why not do:

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

Upvotes: 3

Serodis
Serodis

Reputation: 2112

You could always meet the loops expectations:

if (something) B = 10

Edit: (Appears you included this in your post through an edit)

If you don't like the way it looks, you could wrap a function such as:

Satisfy(B,10)

Then it looks cleaner, but really not needed.

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1062580

I would refactor this to a method, and just call return whenever I need to.

You could also use goto, and I have used goto for this, but it gets frowned upon. Which is dumb; this scenario is why it exists in the language.

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();

Upvotes: 32

Related Questions