How does `foreach` iterate through a 2D array?

I was curious as to how a foreach loop in C# iterates over a multidimensional array. In the following code, the second nested for loop was originally a foreach which would give the incorrect position of the pitches placed in the loop. I know it's kind of difficult to intuit what it does, but it's basically this: Pitches are put into a multidimensional array (here, numVoices is 2 and exLength is 10) so that you will have a 2x10 array of pitches; each of these rows of pitches are then played at the same time by the MIDI output device. When I used a foreach to then put the pitches' names into a string so that I could display what pitches were in what place inside of the grid, the foreach would display them in the "wrong" order (i.e., [0,3] in the pitch grid was not what was printed in the string). Using a nested for, this problem disappeared. I tried to recreate this with a smaller example of a 2D list of ints (code below) but it gives the "right" answer this time. Why?

            //put pitches into grid
            //numVoices = 2, exLength = 10 (10 notes long, 2 voices)
            for (int i = 0; i < numVoices; i++ )
            {
                for(int j = 0; j < exLength; j++)
                {
                    //here we generate random pitches in different octaves
                    //depending on the voice (voice 2 is in octave
                    //below voice 1, etc)
                    randnum = (random.Next(100 - (i * 13), 112 - (i * 13)));                        

                    melodyGrid[j, i] = (Pitch)randnum;

                }
            }

            for (int i = 0; i < numVoices; i++)
            {
                for (int j = 0; j < exLength; j++)
                {
                                     //this down here makes it more readable for
                                     //humans
                                     //e.g. "FSharp5" becomes "F#5"

                    noteNames += String.Format("{0, -6}", melodyGrid[j,i].ToString().Replace("Sharp", "#").Replace("Flat", "b"));

                }
                noteNames += "\r\n"; //lower voices are just separated by newlines
            }
            Console.WriteLine(noteNames);

The following code works "correctly," however:

int[,] nums = { {1, 2, 3}, 
                            {4, 5, 6},
                            {7, 8 ,9} };
            foreach (int i in nums)
            {
                Console.Write("{0} ", i);
            }

Is it possible I was just making a semantic mistake? Or do foreach loops iterate through arrays in differing manners?

Jon Skeet
people
quotationmark

I was curious as to how a foreach loop in C# iterates over a multidimensional array.

As always for questions like this, the ultimate authority is the C# language specification. In this case, section 8.8.4:

The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length – 1. For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.

Now, compare that with how you're iterating with your for statements:

for (int i = 0; i < numVoices; i++ )
{
    for(int j = 0; j < exLength; j++)
    {
        ...
        melodyGrid[j, i] = (Pitch)randnum;

In other words, you're incrementing the leftmost dimension first... so yes, this will give a different result from foreach. If you want to use foreach but get the same iteration order, you'll need to switch the indexes for voices and length. Alternatively, if you want to keep the same order of indexes, just use the for loop and be happy with it.

people

See more on this question at Stackoverflow