#1,197 – Iterator Can Generate Enumerable of Infinite Length

An iterator can be written to generate an enumerable sequence of infinite length.  The iterator will execute for as long as client code continues to request the next element in the sequence.

Below is a simple iterator that generates prime numbers.  Note that we can still use the iterator, although its implementation includes an infinite loop.  The loop will execute only as many times as needed.

        static void Main(string[] args)
        {
            Console.Write("Enter limit:");
            int limit = int.Parse(Console.ReadLine());

            foreach (int p in AllPrimes())
            {
                if (p > limit)
                    break;
                Console.WriteLine(p);
            }

            Console.ReadLine();
        }

        private static IEnumerable<int> AllPrimes()
        {
            List<int> primesSoFar = new List<int>();
            primesSoFar.Add(2);
            yield return 2;
            primesSoFar.Add(3);
            yield return 3;

            int testPrime = 5;
            while (true)
            {
                bool isPrime = true;
                foreach (int n in primesSoFar)
                {
                    if (testPrime % n == 0)
                    {
                        isPrime = false;
                        break;
                    }
                }

                if (isPrime)
                {
                    primesSoFar.Add(testPrime);
                    yield return testPrime;
                }

                testPrime += 2;
            }
        }

1197-001

Advertisement

#1,196 – Using Fluent-Style Syntax when Chaining Iterators

You can chain iterator code together using a fluent-style syntax if you define extension methods for the corresponding IEnumerable<T> type that you’re using.  In the code below, we chain several iterators together, progressively filtering an IEnumerable<Dog> collection.

    class Program
    {
        static void Main(string[] args)
        {
            foreach (Dog d in AllMyDogs().YoungDogs().HerdingDogs())
            {
                Console.WriteLine(d);
                if (d.Breed == Breed.JackRussell)
                    break;
            }

            Console.ReadLine();
        }

        private static IEnumerable<Dog> AllMyDogs()
        {
            yield return new Dog("Kirby", Breed.BorderCollie, 14);
            yield return new Dog("Jack", Breed.JackRussell, 15);
            yield return new Dog("Ruby", Breed.Mutt, 4);
            yield return new Dog("Lassie", Breed.Collie, 19);
            yield return new Dog("Shep", Breed.Collie, 2);
            yield return new Dog("Foofoo", Breed.Sheltie, 8);
            yield return new Dog("Pongo", Breed.Dalmatian, 4);
            yield return new Dog("Rooster", Breed.WestHighlandTerrier, 1);
        }
    }

    static class DogFilters
    {
        public static IEnumerable<Dog> YoungDogs(this IEnumerable<Dog> dogs)
        {
            foreach (Dog d in dogs)
                if (d.Age < 10)
                    yield return d;
        }

        public static IEnumerable<Dog> HerdingDogs(this IEnumerable<Dog> dogs)
        {
            foreach (Dog d in dogs)
                if ((d.Breed == Breed.BorderCollie) ||
                    (d.Breed == Breed.Collie) ||
                    (d.Breed == Breed.Sheltie))
                    yield return d;
        }
    }

Here’s the output:
1196-001

#1,195 – Iterator Produces Only as Many Elements as Are Needed

When implementing an iterator, you write code that generates a sequence of elements using the yield return statement to return each consecutive element.

The full body of the iterator code may not execute.  Only the code required to return the elements iterated upon is executed.  In the example below, we iterate over a sequence produced by an iterator, using foreach.

Executing this code, only a portion of the AllMyDogs() method is executed, since we exit early out of  the foreach loop.

            static void Main(string[] args)
            {
                foreach (Dog d in AllMyDogs())
                {
                    Console.WriteLine(d);
                    if (d.Breed == Breed.JackRussell)
                        break;
                }

                Console.ReadLine();
            }

            private static IEnumerable<Dog> AllMyDogs()
            {
                Console.WriteLine("* returning Kirby");
                yield return new Dog("Kirby", Breed.BorderCollie, 14);
                Console.WriteLine("* returning Jack");
                yield return new Dog("Jack", Breed.JackRussell, 15);
                Console.WriteLine("* returning Ruby");
                yield return new Dog("Ruby", Breed.Mutt, 4);
                Console.WriteLine("* returning Lassie");
                yield return new Dog("Lassie", Breed.Collie, 12);
                Console.WriteLine("* returning Foofoo");
                yield return new Dog("Foofoo", Breed.Sheltie, 8);
            }

1195-001

#1,194 – Chaining Iterators Together

An iterator can work on an IEnumerable<T>, using one sequence as input and generating a second sequence from the first.

In the example below, we use the output of one iterator as the input for another iterator.

        static void Main(string[] args)
        {
            IEnumerable<Dog> dogs1 = AllMyDogs();

            Console.WriteLine("============");
            foreach (Dog d in dogs1)
                Console.WriteLine(d);

            IEnumerable<Dog> dogs2 = YoungDogs(dogs1);

            Console.WriteLine("============");
            foreach (Dog d in dogs2)
                Console.WriteLine(d);

            IEnumerable<Breed> breeds = BreedsByNamePattern(dogs2, "oo");

            Console.WriteLine("============");
            foreach (Breed b in breeds)
                Console.WriteLine(b);

            Console.ReadLine();
        }

        private static IEnumerable<Dog> AllMyDogs()
        {
            yield return new Dog("Kirby", Breed.BorderCollie, 14);
            yield return new Dog("Jack", Breed.JackRussell, 15);
            yield return new Dog("Ruby", Breed.Mutt, 4);
            yield return new Dog("Lassie", Breed.Collie, 12);
            yield return new Dog("Foofoo", Breed.Sheltie, 8);
            yield return new Dog("Pongo", Breed.Dalmatian, 4);
            yield return new Dog("Rooster", Breed.WestHighlandTerrier, 1);
        }

        private static IEnumerable<Dog> YoungDogs(IEnumerable<Dog> dogs)
        {
            foreach (Dog d in dogs)
                if (d.Age < 10)
                    yield return d;
        }

        private static IEnumerable<Breed> BreedsByNamePattern(IEnumerable<Dog> dogs, string pattern)
        {
            foreach (Dog d in dogs)
                if (d.Name.Contains(pattern))
                    yield return d.Breed;
        }

1194-001

#1,193 – yield Statement and try/catch Blocks

The yield return statement is used when defining an iterator to generate the next element within a sequence (IEnumerable).  You cannot include a yield return statement in any of the following places:

  • within a try block that has a catch clause
  • within a catch block
  • within a finally block

You can include a yield return statement within a try block that only has a finally block.

        private static IEnumerable<int> IntsAndTheirDoubles()
        {
            for (int i = 1; i <= 5; i++ )
            {
                yield return i;
                try
                {
                    // Error: Cannot yield a value in the body of a try block
                    //   with a catch clause
                    yield return 2 * i;
                }
                catch (Exception xx)
                {
                    Console.WriteLine("Uh-oh");
                }
            }
        }

#565 – Using an Iterator to Return A Shuffled Sequence

The System.Linq namespace includes an OrderBy method that makes it easy to reorder an enumerable sequence, based on a particular key.  For a key, we can use a newly generated Guid to achieve a random order.  (See Jeff Atwood’s post on Shuffling).

We can encapsulate this shuffling behavior in a method that returns the resulting shuffled sequence as an IEnumerable. We’ll use an iterator in the body of this method to return the shuffled sequence of elements.

        // Two line shuffle
        static IEnumerable<int> Shuffle(List<int> theList)
        {
            foreach (int next in theList.OrderBy(x => Guid.NewGuid()))
                yield return next;
        }

You can now use this method to iterate through the original sequence in a random order.  You can also view this as moving through a newly shuffled sequence.  Note that the original list is not re-ordered.

            List<int> myList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            foreach (int i in Shuffle(myList))
                Console.WriteLine(i);

#564 – Use the Reverse Method to Iterate Backwards through a Collection

You can use the Enumerable<TSource>.Reverse method on any enumerable object, to iterate backwards through its collection.

Because arrays and collections implement the IEnumerable interface, you can use a foreach statement to enumerate through their elements in a forward-only fashion.

            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            foreach (int i in nums)
                Console.WriteLine(i);

The default enumerator implemented in types like System.Array and List<T>, however, only allows you to iterate forwards through a collection.  If you instead want to iterate backwards through an array or collection, you can use the Reverse method mentioned above. This method is part of System.Linq and is an extension method that works on any IEnumerable<T> type.

            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            foreach (int j in nums.Reverse())
                Console.WriteLine(j);

            List<Dog> myDogs = new List<Dog>();
            myDogs.Add(new Dog("Jack", 17));
            myDogs.Add(new Dog("Kirby", 15));
            myDogs.Add(new Dog("Ruby", 1));

            foreach (Dog d in myDogs.Reverse<Dog>())
                Console.WriteLine(d.Name);

#563 – Enumerable Types Can Generate Multiple Enumerators

Each time that the GetEnumerator method in an enumerable type is called, an independent enumerator is generated.  Each enumerator keeps track of its own position in the parent sequence.

In the example below, nested foreach statements each iterate over the same collection.  The outer foreach statement results in one enumerator and the inner foreach statement results in the generation of a new enumerator for each pass of the outer foreach.

In this case, the ability to generate multiple independent enumerators is necessary, so that we can have overlapping foreach statements.

            int[] nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            foreach (int i in nums)
                foreach (int j in nums)
                    Console.WriteLine("{0} x {1} = {2}", i, j, i * j);

#562 – What an Iterator Looks Like Under the Covers

When you use an iterator to return an enumerable sequence of items, the C# compiler converts your iterator block (containing one or more yield return statements) into a new class that performs the actual enumeration.  The new class actually implements all four interfaces that an iterator can return–IEnumerableIEnumerable<T>IEnumerator and IEnumerator<T>.

Below is a simple iterator block that returns a sequence of two elements.

        private static IEnumerable<int> MyIterator()
        {
            yield return 100;
            yield return 200;
        }

If you use a disassembler to look at the IL that the compiler generates for this code, you’ll see a new class that implements the four interfaces.

You’ll notice that the class implements GetEnumerator, which just returns the current instance of the class.  (Code shown is from Reflector).

The MoveNext method returns the next element in the sequence.

#561 – Using a yield break Statement

When implementing an iteratorthe yield return statement returns the next element in the sequence being returned.  If you are using a loop within the iterator block, you can use the yield break statement to break out of the loop, indicating that no more elements are to be returned.

In the example below, an iterator is used to return a portion of the Fibonacci sequence.  yield break is used to break out of the loop generating the sequence.

        static void Main()
        {
            // Return Fibonacci numbers below 2,000
            foreach (int i in Fibonacci(2000))
                Console.WriteLine(i);

            int gi = 12;
        }

        private static IEnumerable<int> Fibonacci(int maxValue)
        {
            yield return 0;
            yield return 1;

            int last = 0;
            int current = 1;

            while (true)
            {
                int next = last + current;
                if (next > maxValue)
                    yield break;
                else
                {
                    yield return next;
                    last = current;
                    current = next;
                }
            }
        }