tags:

views:

144

answers:

2

After answering this question I put together the following C# code just for fun:

public static IEnumerable<int> FibonacciTo(int max)
{     
    int m1 = 0;
    int m2 = 1;
    int r = 1;

    while (r <= max)
    {
       yield return r;

       r = m1 + m2;
       m1 = m2;
       m2 = r;
    }
}

foreach (int i in FibonacciTo(56).Where(n => n >= 24) )
{
   Console.WriteLine(i);
}

The problem is that I don't like needing to pass a max parameter to the function. Right now, if I don't use one the code will output the correct data but then appear to hang as the IEnumerable continues to work. How can I write this so that I could just use it like this:

foreach (int i in Fibonacci().Where(n => n >= 24 && n <= 56) )
{
   Console.WriteLine(i);
}
A: 

I don't think this is possible unless you write your own LINQ provider. In the example you gave you are using LINQ to Objects which will need to completely evaluate the IEnumerable before it can apply a filter to it.

John Downey
Thankfully IEnumerable doesn't really work like that: it applies the filter as it evaluates so data is streamed rather than repeated.
Joel Coehoorn
Joel you are correct, I forgot my basic principals of functional programing where an operation cannot have a side effect.
John Downey
+9  A: 

You need to use a combination of SkipWhile and TakeWhile instead.

foreach (int i in Fibonacci().SkipWhile(n => n < 24)
                             .TakeWhile(n => n <= 56))
{
   Console.WriteLine(i);
}

These are able to end loops depending on a condition; Where streams its input (filtering appropriately) until the input runs out (in your case, never).

Jon Skeet
I had just figured this out and was about to post it myself. Odd how finally writing out the question sometimes points you to the obvious
Joel Coehoorn
Hmm... my basic problem is that I was fixated on doing this in only one lambda expression. Now I'm tempted to also write a new "SkipThenTakeWhile()" IEnumerable extension that would allow that, if only I can think of a better name for it ;)
Joel Coehoorn
While I enjoy writing LINQ operators too, I'd question whether this really comes up often enough to merit one ;)
Jon Skeet