#1,124 – Iterate through Jagged Array with Nested foreach

You can’t use the foreach statement to directly iterate over all elements in a jagged array.  You can, however, iterate through the jagged array using nested foreach statements.  Each foreach statement independently iterates over one dimension of the jagged array.

            // Jagged array - 3 elements, each of which is array of int
            int[][] nums = new int[3][];

            nums[0] = new int[4];
            nums[2] = new int[3];

            for (int i = 0; i < 4; i++)
                nums[0][i] = i + 1;

            for (int i = 0; i < 3; i++)
                nums[2][i] = i + 101;

            // Iterate using foreach
            foreach (int[] intArray in nums)
            {
                if (intArray != null)
                {
                    Console.WriteLine("Array with {0} elements", intArray.Length);
                    foreach (int n in intArray)
                        Console.WriteLine("  {0}", n);
                }
                else
                    Console.WriteLine("Found null array");
            }

1124-001

Advertisements

#1,123 – Using foreach to Iterate on a Multidimensional Array

You can use the foreach statement to iterate through all elements in a multidimensional array.  The elements are iterated in a row-major order.  That is, all elements in the first row are enumerated, followed by the second row, etc.

            // 2-dimensional array
            string[,] twoByThree = new string[2, 3];

            // Populate with standard for loop
            for (int row = 0; row < 2; row++)
                for (int col = 0; col < 3; col++)
                    twoByThree[row, col] = string.Format("{0}/{1}", row + 1, col + 1);

            // Iterate using foreach
            foreach (string s in twoByThree)
                Console.WriteLine(s);

1123-001

#1,122 – It’s Okay to Capture Variables within a foreach Loop

Within a foreach loop, you capture an iteration variable when you save it for later use.  In versions of C# earlier than 5.0, this led to problems and unexpected behavior.  What ended up being captured was multiple copies of the last value of the iteration variable.

This has been changed in C# 5.0 so that you can capture an iteration variable within a foreach loop and get the expected behavior.

            string[] beatles = {"George", "John", "Paul", "Ringo"};

            List<Action> actionList = new List<Action>();
            List<string> guyList = new List<string>();

            foreach (string guy in beatles)
            {
                guyList.Add(guy);
                actionList.Add(() => Console.WriteLine(guy));
            }

            foreach (string guyInList in guyList)
                Console.WriteLine(guyInList);

            Console.WriteLine("===");

            foreach (Action a in actionList)
                a();

1122-001

#1,121 – Modifying Elements in a Collection Using foreach

Although the iteration variable in a foreach loop is read-only, you can still use the iteration variable to modify the elements of a collection, as long as they are reference-typed.  (Value-typed elements are immutable).  You’re not changing the iteration variable, but rather changing the object that it refers to.

            List<Dog> myDogs = new List<Dog>
                {
                    new Dog {Name = "Kirby", Age = 15},
                    new Dog {Name = "Ruby", Age = 2},
                    new Dog {Name = "Jack", Age = 17}
                };

            foreach (Dog d in myDogs)
            {
                Console.Write(string.Format("{0} / ", d));
                d.Age++;
                Console.WriteLine(d);
            }

1121-001

#1,120 – The Iteration Variable in a foreach Loop Is Read-Only

Unlike the for loop, the iteration variable in a foreach loop is read-only.  Attempting to assign a value to the variable within the body of the loop will result in a compile-time error.

            string[] dogs = {"Kirby", "Jack", "Ruby", "Lassie"};

            // for loop allows writing to iteration variable
            Console.WriteLine("= for loop");
            for (int i = 0; i < dogs.Length; i++)
            {
                Console.WriteLine(dogs[i]);
                if (dogs[i].StartsWith("J"))
                    i++;  // skip next
            }

            Console.WriteLine("= foreach loop");
            foreach (string s in dogs)
            {
                if (s.StartsWith("J"))
                    s = "****";     // ERROR
                Console.WriteLine(s);
            }

1120-001

#1,119 – Scope of Iteration Variable Is Limited to Body of foreach

The iteration variable that is set to a new element during each pass of a foreach statement only has scope within the body of the foreach loop.  It may not be used or referenced outside of the loop.

            List<Dog> myDogs = new List<Dog>
                {
                    new Dog {Name = "Kirby", Age = 15},
                    new Dog {Name = "Ruby", Age = 2},
                    new Dog {Name = "Jack", Age = 17}
                };

            foreach (Dog d in myDogs)
            {
                Console.WriteLine(d);
                d.Age++;
            }

            // Compile Error: The name 'd' does not exist in the current context
            string someDog = d.Name;

#1,118 – foreach Works with Iterator Returned by yield

You can use the yield keyword in a method to implement an iterator.  The method in which it is defined returns an IEnumerable or IEnumerator.  The resulting iterator can be consumed using the foreach statement.

Below is an example of a method that returns an IEnumerable<T> which can then be iterated upon using a foreach statement.

        static IEnumerable<Dog> DogsWithKids(IEnumerable<Dog> dogList)
        {
            foreach (Dog d in dogList)
            {
                yield return d;
                yield return new Dog(d.Name + " Jr.",
                                     Math.Max(d.Age - 3, 1));
            }
        }

        static void Main(string[] args)
        {
            List<Dog> myDogs = new List<Dog>
                {
                    new Dog {Name = "Kirby", Age = 15},
                    new Dog {Name = "Ruby", Age = 2}
                };

            // Iterate through dogs w/offsprings
            foreach (Dog d in DogsWithKids(myDogs))
                Console.WriteLine(d);

            Console.ReadLine();
        }

The result is a sequence with twice as many elements as the original List<T>.

1118-001