tags:

views:

1493

answers:

13

As a trivial example lets say I have the following grid and I am looking for a particular cells value. When found I no longer need to process the loops.

foreach(DataGridViewRow row in grid.Rows)
{
    foreach(DataGridViewCell cell in row.Cells)
    {
        if(cell.Value == myValue)
        {
            //Do Something useful
            //break out of both foreach loops.
        }
    }
}

How is this done in C#. In Java I could use a label to name the outermost loop, and then break that loop, but I can't seem to find an equivelant in C#.

What is the tersest way of accomplishing this in c#? I know I can set a boolean flag, and check it in the outer loop to break out of that one as well, but it just seems too verbose.

Thanks,

+7  A: 

C# does have a goto statement. In fact, the example on MSDN uses it to break out of a doubly-nested loop.

PeterAllenWebb
I was going to suggest this until I remembered http://xkcd.com/292/But yes, a goto could solve the problem.
Chet
the fact it's used in MSDN doesn't mean it's the best way of doing things (as many other examples there), i'm still at the avoid gotos whenever you can point of view, this problem can be solved in other ways (primarily extracting the logic into the separate function and returning the function)
zappan
+6  A: 

The best way is to not do this. Seriously; if you want to find the first occurrence of something in your nested loops, and then finish looking, then what you want to do is NOT to examine each element, which is explicitly just what the foreach construct does. I'd recommend using a regular for loop with a termination flag in the loop invariant.

McWafflestix
+15  A: 

I'd just wrap the loops into a function and have the function return as a way to exit the loops for my solution.

JB King
Beat me by a few seconds.
Joel Coehoorn
Beat me by a few seconds, but I wrote a nice example, so mine's staying!
mquander
Why the downvote? He is just saying what mquander suggests, but without a code example.
Matthew Vines
this sort of method is not always completely viable, particularly if you have a complicated set of evaluations on your cells to do in the loop dependent upon other things in your method.
McWafflestix
I thought I'd leave writing the code as an exercise for the person posing the question. :)
JB King
@McWafflestix this method is vastly preferable though. If you start getting tangled up code, that's an indication that you're doing something the wrong way. Clean code that's understandable will have fewer defects, generally, because it's easier to test and because it's easier to see when it's wrong.
Wedge
+16  A: 

The most pleasant way is to break the second loop out into a function, like this:

public void DoubleLoop()
{
    for(int i = 0; i < width; i++)
    {
        for(int j = 0; j < height; j++)
        {
            if(whatever[i][j]) break; // let's make this a "double" break
        }
    }
}

goes to

public bool CheckWhatever(int whateverIndex)
{
    for(int j = 0; j < height; j++)
    {
        if(whatever[whateverIndex][j]) return false;
    }

    return true;
}

public void DoubleLoop()
{
    for(int i = 0; i < width; i++)
    {
        if(!CheckWhatever(i)) break;
    }
}

Of course, feel free to simplify this with LINQ or whatever (you could put CheckWhatever into the loop condition, too.) This is just a verbose demonstration of the principle.

mquander
Gets the accepted flag for adding in the example. Thanks all who responded.
Matthew Vines
This is slightly different from my answer which was that you could keep both loops rolled into one function where here there are 2 functions, each containing just one loop.
JB King
A: 
  1. Use go to as PeterAllenWebb as suggested.
  2. Wrap the two for each loop into a function, and return when you want to break.

Did a bit google search, here is a similar question on MSDN forum.

J.W.
+1 for suggestion #2. not sure why anyone would -1 this
dss539
+10  A: 
        foreach (DataGridViewRow row in grid.Rows)
        {
            foreach (DataGridViewCell cell in row.Cells)
            {
                if (cell.Value == myValue)
                {
                    goto EndOfLoop;
                    //Do Something useful
                    //break out of both foreach loops.
                }
            }

        }
        EndOfLoop: ;

that will work, but I would recommend using a boolean flag.

EDIT: Just to add a little more warning here; it is generally considered bad practice to use goto's as they quickly can lead to spaghetti code that is (nearly) impossible to maintain. That being said, it was included in the C# language, and is available for use, so clearly there are people who believe it has valid usages. Know that the feature exists and use with great caution.

Timothy Carter
why was this voted down?
Jimmy
Even though I'd never use a goto myself, I was wondering the same thing... The answer by PeterAllenWebb got 2 upvotes for basically the same answer. This one's actually a better answer too (in terms of providing a usage example). Odd.
Pwninstein
+22  A: 

1

foreach(DataGridViewRow row in grid.Rows)
   foreach(DataGridView cell in row.Cells)
      if (cell.Value == somevalue) {
         // do stuff
         goto End:
      }
End:
   // more stuff

2

void Loop(grid) {
    foreach(row in grid.Rows)
       foreach(cell in row.Cells)
           if (something) {
               // do stuff   
               return;
           }
}

3

var cell = (from row in grid.Rows.OfType<DataGridViewRow>()
            from cell in row.Cells.OfType<DataGridViewCell>()
            where cell.Value == somevalue
            select cell
   ).FirstOrDefault();

if (cell != null) {
   // do stuff
}
Jimmy
what? ahh. cool!
rizzle
*big sigh* for pre-generic collections and OfType<>(). Also, proper placement of indentation for linq is beyond me.
Jimmy
+1 for goto. People today are scared of goto, but this is a legitimate use of one.
rlbond
I made the mistake of mentioning goto for a similar problem and got downvotes. But using the break keyword is pretty much the same thing as calling a goto to the end of the loop, no?
Meta-Knight
@Meta-Knight: while you're at it, multiple returns from a function is equivalent to a goto. its just less messy because it imposes the restriction that you can't do upwards goto, or jump over a goto label (both types degenerate quickly into chaos)
Jimmy
@Jimmy every control structure is equivalent to a goto. Similarly, every program you write in Python, Ruby, C#, or Lisp can be duplicated exactly in assembly code or raw machine code. Languages are constructs which bridge the gap between computing hardware and human developers, it's important to recognize that returning a value from a function is a design pattern which has much different implications in how it will be used than a simple goto, even if they share implementation similarities under the hood.
Wedge
+2  A: 
  //describe how to find interesting cells
var query = from row in grid.Rows.OfType<DataGridViewRow>()
            from cell in row.Cells.OfType<DataGridViewCell>()
            where cell.Value == myValue
            select cell;
  //nab the first cell that matches, if any
DataGridViewCell theCell = query.FirstOrDefault();

  //see if we got one
if (theCell != null)
{
  //Do something with theCell
}
David B
A: 

Put that into a function & use a return statement, when things are found.
At the end of it return a null value - indicating searched item not found.

shahkalpesh
A: 

You could modify your loop variable:

for (int i = 0; i < width; i++)
{
    for (int j = 0; j < height; j++)
    {
        if (NeedToBreak())
        {
            i = width;
            j = height; 
        }
    }

}
Alan Jackson
+4  A: 

For completeness, there's also the wrong way to do it:

try
{
    foreach(DataGridViewRow row in grid.Rows)
        foreach(DataGridViewCell cell in row.Cells)
            if(cell.Value == myValue)
               throw new FoundItemException(cell);
}
catch (FoundItemException ex)
{
    //Do Something useful with ex.item
}
Eclipse
+5  A: 

You can write a class that implements IEnumerator<T> in the general case and then your enumeration code looks like this:

foreach (Foo foo in someClass.Items) {
    foreach (Bar bar in foo.Items) {
        foreach (Baz baz in bar.Items) {
            yield return baz;
        }
    }
}

// and later in client code

MyEnumerator e = new MyEnumerator(someClass);
foreach (Baz baz in e) {
    if (baz == myValue) {
        // do something useful
        break;
    }
 }
plinth
+27  A: 

Though many of the solutions above are correct and answer your question, I would take a step back and ask myself "is there another way to more clearly represent the semantics of the program?"

I would be inclined to write the code like this:

var query = from row in grid.Rows
            from cell in row.Cells
            where cell.Value == myValue
            select cell;
if (query.Any())
{
  // do something useful;
}

Why write any loops at all? You want to know if a particular collection has a particular member, so write a query that asks that question, and then examine the answer.

Eric Lippert
This is a good thinking.
J.W.
Now that's slick! +1
RCIX
Very good Eric, I like your thinking :-)
DoctaJonez