none
C# Syntax: Breaking out of two nested foreach loops

    Question

  • Is there a neat and tidy way to break out of two nested foreach loops in C#?

     

    Here is my scenario:

     

    // Get a list of integers

    List<int> list1 = new List<int>();

    list1.AddRange(new int[] { 1, 4, 8, 9, 14 });

     

    // Get another list of integers

    List<int> list2 = new List<int>();

    list2.AddRange(new int[] {2, 3, 5, 8, 11, 12});

     

    // Return the first match found by comparing the elements in the lists

    int firstMatch = -1;

     

    foreach (int outerItem in list1)

    {

    foreach (int innerItem in list2)

    {

    if (outerItem == innerItem)

    {

    firstMatch = innerItem;

    break; /* I actually want to break out of BOTH loops, not

    just this inner one. */

    }

    }

    }

     

    // Write out the result

    Console.WriteLine(firstMatch.ToString());

     

    I have a solution that works fine, but I want to know if there's a neater way to do it than this....

     

    // Get a list of integers

    List<int> list1 = new List<int>();

    list1.AddRange(new int[] { 1, 4, 8, 9, 14 });

     

    // Get another list of integers

    List<int> list2 = new List<int>();

    list2.AddRange(new int[] {2, 3, 5, 8, 11, 12});

     

    // Return the first match found by comparing the elements in the lists

    int firstMatch = -1;

     

    foreach (int outerItem in list1)

    {

    foreach (int innerItem in list2)

    {

    if (outerItem == innerItem)

    {

    firstMatch = innerItem;

    break; /* Just break out of the inner loop and have the outer loop perform a check on the result before it continues. */

    }

    }

     

    if (firstMatch != -1)

    {

    break; /* Check whether or not the first loop got a result, by comparing the firstMatch variable to its default value. In more complicated scenarios, I could use a boolean variable to flag whether or not a match had been found yet */

    }

    }

     

    // Write out the result

    Console.WriteLine(firstMatch.ToString());

     

     

    If anybody knows of a snippet or statement in C# that I could use to make this neater, please could you let me know?

     

     

    Many thanks in advance.

    Thursday, May 08, 2008 9:19 AM

Answers

  • There is no way of using break to break out of multiple loops. The break command will allways just apply to the inner most loop.
    I would probably do the same thing that your doing, but you could also use "goto".

     

     

     

    Code Snippet

    // Get a list of integers

    List<int> list1 = new List<int>();

    list1.AddRange(new int[] { 1, 4, 8, 9, 14 });

     

    // Get another list of integers

    List<int> list2 = new List<int>();

    list2.AddRange(new int[] {2, 3, 5, 8, 11, 12});

     

    // Return the first match found by comparing the elements in the lists

    int firstMatch = -1;

     

    foreach (int outerItem in list1)

    {

    foreach (int innerItem in list2)

    {

    if (outerItem == innerItem)

    {

    goto BreakLoops;

    }

    }

    }

     

    BreakLoops:

    //Code continuse here

     

     

     

    Thursday, May 08, 2008 9:40 AM
  • Your welcome

    But if your using C# 3.0 you could also use linq and just skip the loops

     

    something like this

     

    // Get a list of integers

    List<int> list1 = new List<int>();

    list1.AddRange(new int[] { 1, 4, 9, 14 });

     

    // Get another list of integers

    List<int> list2 = new List<int>();

    list2.AddRange(new int[] { 2, 3, 5, 8, 11, 12 });

     

    int firstMatch = list1.FirstOrDefault(a => a == list2.Where(b => b == a).Select(c => c).FirstOrDefault() );

     

    // Write out the result

    Console.WriteLine(firstMatch.ToString());

    Thursday, May 08, 2008 10:39 AM
  • You could put just the search logic into a function:

    public int FirstMatch(IEnumerable<int> set1, IEnumerable<int> set2)
    {
        foreach (int n1 in set1)
        {
            foreach (int n2 in set2)
            {
                if (n1 == n2)
                {
                    return n1;
                }
            }
        }

        return -1; // No matches.
    }

    This isn't really structured, since it has a return in the middle of a nested loop; but for simple short things like this it is probably acceptable, and it is easy to understand the code.
    Thursday, May 08, 2008 12:06 PM
  • Predicate delegates to the rescue!

     

    Code Snippet

    foreach (int outerItem in list1) {

        firstMatch = list2.Find(delegate(int i) {

            return i == (int)outerItem;

        });

     

        if (firstMatch != 0) {

            break;

        }

    }

     

     

    Thursday, May 08, 2008 3:42 PM

All replies

  • There is no way of using break to break out of multiple loops. The break command will allways just apply to the inner most loop.
    I would probably do the same thing that your doing, but you could also use "goto".

     

     

     

    Code Snippet

    // Get a list of integers

    List<int> list1 = new List<int>();

    list1.AddRange(new int[] { 1, 4, 8, 9, 14 });

     

    // Get another list of integers

    List<int> list2 = new List<int>();

    list2.AddRange(new int[] {2, 3, 5, 8, 11, 12});

     

    // Return the first match found by comparing the elements in the lists

    int firstMatch = -1;

     

    foreach (int outerItem in list1)

    {

    foreach (int innerItem in list2)

    {

    if (outerItem == innerItem)

    {

    goto BreakLoops;

    }

    }

    }

     

    BreakLoops:

    //Code continuse here

     

     

     

    Thursday, May 08, 2008 9:40 AM
  • Thanks very much, Gaui. I thought that was the case.

    Thursday, May 08, 2008 9:50 AM
  • Your welcome

    But if your using C# 3.0 you could also use linq and just skip the loops

     

    something like this

     

    // Get a list of integers

    List<int> list1 = new List<int>();

    list1.AddRange(new int[] { 1, 4, 9, 14 });

     

    // Get another list of integers

    List<int> list2 = new List<int>();

    list2.AddRange(new int[] { 2, 3, 5, 8, 11, 12 });

     

    int firstMatch = list1.FirstOrDefault(a => a == list2.Where(b => b == a).Select(c => c).FirstOrDefault() );

     

    // Write out the result

    Console.WriteLine(firstMatch.ToString());

    Thursday, May 08, 2008 10:39 AM
  • Cheers. That's another good solution. I'll bear it in mind.

     

    Thursday, May 08, 2008 10:50 AM
  • Wrap it in functions and use "return".

    Thursday, May 08, 2008 11:30 AM
  • You could put just the search logic into a function:

    public int FirstMatch(IEnumerable<int> set1, IEnumerable<int> set2)
    {
        foreach (int n1 in set1)
        {
            foreach (int n2 in set2)
            {
                if (n1 == n2)
                {
                    return n1;
                }
            }
        }

        return -1; // No matches.
    }

    This isn't really structured, since it has a return in the middle of a nested loop; but for simple short things like this it is probably acceptable, and it is easy to understand the code.
    Thursday, May 08, 2008 12:06 PM
  • I had intended to use this logic in a function. I left it inline just for the sake of my example, but you're right. It would also be better as a generic function so it needn't work with integers.

     

    I don't particularly like the multiple return statements, which is why I asked the question, but I suppose, like you say, in a simple function they're not too much of a problem.

     

    Thanks to both of you for your input.

    Thursday, May 08, 2008 12:42 PM
  • Predicate delegates to the rescue!

     

    Code Snippet

    foreach (int outerItem in list1) {

        firstMatch = list2.Find(delegate(int i) {

            return i == (int)outerItem;

        });

     

        if (firstMatch != 0) {

            break;

        }

    }

     

     

    Thursday, May 08, 2008 3:42 PM
  • There are more solutions than I expected! Thanks.

    Thursday, May 08, 2008 3:46 PM
  •  Ron.Whittle wrote:
    Predicate delegates to the rescue!


    Oh, that's a point - we could use Contains() instead of Find() for even greater simplicity! The original code would then become:

    // Get a list of integers

    List<int> list1 = new List<int>();

    list1.AddRange(new int[] { 1, 4, 8, 9, 14 });

     
    // Get another list of integers

    List<int> list2 = new List<int>();

    list2.AddRange(new int[] {2, 3, 5, 8, 11, 12});

    // Return the first match found by comparing the elements in the lists

    int firstMatch = -1;

     
    foreach (int outerItem in list1)
    {
        if (list2.Contains(outerItem)
        {
            firstMatch = outerItem;
            break;
        }
    }

    // Write out the result

    Console.WriteLine(firstMatch.ToString());

    Thursday, May 08, 2008 11:33 PM