For this demonstration, we'll be creating a lazy-calculated
prime number generator based on Mike's code. First, we'll be needing a
utility method to generate a steady stream of numbers (we only need odd numbers
after 2)
public static IEnumerable<Int32> Counter(Int32 start, Int32 step, Int32 min, Int32 max)
{
Int32 current = start;
while (current > min && current <
max)
{
yield return
current;
current += step;
}
}
Next, we'll need a method that will tap into our program flow
to perform some processing but not inturrupt the output.
public static IEnumerable<T> PassThrough<T>(this IEnumerable<T> items, Action<T> act)
{
foreach (T item in
items)
{
act(item);
yield return
item;
}
}
These two simple methods will allow us to generate all the
prime numbers that can be expressed with an Int32 variable.
public static IEnumerable<Int32> GetPrimes()
{
List<Int32> found = new List<int>();
return
new Int32[]
{ 2 }
.Concat(Helpers.Counter(3, 2, 0, Int32.MaxValue))
.Where(i => !found.Exists(j => i % j == 0))
.PassThrough(k => found.Add(k));
}
Let's examine what is happening in the code. First,
we'll start with the number 2 and then append all the odd numbers from three
through Int32.MaxValue. As each of
the numbers is generated and passed through the function chain, we'll check to
see if it is evenly divisible by any item in the collection of primes we are
accumulating. If not, it is a new prime and we'll add it to our "found"
list and pass it through using the iterator in the "PassThrough()" extension
method.
The really cool thing is that we only calculate what's needed
when it is neede which is what gives us "lazy calculation" of our primes. As a
result, when we consume this method and only request the first ten primes, the
minimum amount of computations are be performed to get what we have
requested.
static void Main(string[] args)
{
Helpers
.GetPrimes()
.Take(10)
.ForEach(i => Console.WriteLine(i));
Console.ReadLine();
}
How we consume the GetPrimes() method is key. We have to be
aware of how the algoritm works and be careful not to get the wole list unless
we absolutely need it and then if we do, we have to be aware of how generating
all the primes performs because it could be quite computationally expensive and
we may want to do it asynchronously on another thread (which I'll demonstrate in
an upcoming article).
Just so you don't have to hunt... Mike's cool LINQ code to
generate primes is here.
Until next time,
Happy coding