#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

Advertisement

#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

#1,117 – foreach Requires IEnumerable Implementation

The foreach statement works on an object that implements IEnumerable<T> or IEnumerable.  It also works on an object whose type has a public GetEnumerator method that returns an IEnumerator<T> or IEnumerator.

Below, we’ve defined a new class that implements IEnumerable<T>.

    public class DogPack : IEnumerable<Dog>
    {
        private List<Dog> thePack;

        public DogPack()
        {
            thePack = new List<Dog>();
        }

        public void Add(Dog d)
        {
            thePack.Add(d);
        }

        // Remove arbitrary dog
        public void Cull()
        {
            if (thePack.Count == 0)
                return;

            if (thePack.Count == 1)
                thePack.RemoveAt(0);
            else
            {
                Random rnd1 = new Random();
                int indRemove = rnd1.Next(thePack.Count);
                thePack.RemoveAt(indRemove);
            }
        }

        // IEnumerable<T> implementation

        public IEnumerator<Dog> GetEnumerator()
        {
            return thePack.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

We can now use foreach to iterate on an instance of this class.

            DogPack pack = new DogPack();
            pack.Add(new Dog("Lassie", 8));
            pack.Add(new Dog("Shep", 12));
            pack.Add(new Dog("Kirby", 10));
            pack.Add(new Dog("Jack", 15));
            pack.Cull();

            // Who's left?
            foreach (Dog d in pack)
                Console.WriteLine(d);

1117-001

#1,116 – Iterating Through a String Using the foreach Statement

You can iterate through the individual characters in a string using the foreach statement.  The iteration variable is of type char and is set consecutively to each character within the string as the foreach statement executes.

            string secret = "Kint is Keyser Soze";

            StringBuilder sbObfuscate = new StringBuilder();

            foreach (char c in secret)
                sbObfuscate.Append((char)(c + 3));

            Console.WriteLine(sbObfuscate);

1116-001

#1,115 – Iterating Through a Collection Using the foreach Statement

In the same way that you can iterate through an array using foreach, you can iterate through the elements of a collection one at a time.  You do this by writing a loop–a block of code that is executed more than once, executing once for each element in the collection. This is done using the C# foreach statement.

The foreach statement declares a variable local to the loop of the same type of the elements in the collection.  This variable takes on the value of each element in the collection.

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

            // Output using overridden ToString() method
            foreach (Dog d in myDogs)
                Console.WriteLine(d);
1115-001