LINQ – TakeWhile and SkipWhile methods

I happened to read about these methods on Vikram's blog and tried testing it. Somehow when I saw the output, things did not seem to add up right. I’m writing this blog to show the actual workings of these methods.

Let’s take the same example as showing in Vikram’s blog and I’ll build around it.

   1: int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
   2:  
   3: foreach(var number in numbers.TakeWhile(n => n < 7))
   4: {
   5:     Console.WriteLine(number);
   6: }

Now, the way I (incorrectly) read the upper bound condition in the foreach loop was: ‘Give me all numbers that pass the condition of n<7’. So I was expecting the answer to be: 5, 4, 1, 3, 2, 0. But when I run the application, I see only: 5, 4, 1,3. Turns out I was wrong (happens at least once a day).

The documentation on the method says ‘Returns elements from a sequence as long as a specified condition is true. To show in code, my interpretation was the below code’:

   1: foreach (var number in numbers)
   2: {
   3:     if (number < 7)
   4:     {
   5:         Console.WriteLine(number);
   6:     }
   7: }

But the actual implementation is:

   1: foreach(var number in numbers)
   2: {
   3:     if(number < 7)
   4:         Console.WriteLine(number);
   5:     else    
   6:         break;
   7:     
   8: }

 

So there it is, another situation where one simple word makes a difference of a whole world.

The SkipWhile method has been implemented in a similar way – ‘Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements’ and not ‘Bypasses elements in a sequence where a specified condition is true and then returns the remaining elements’. (Subtle.. very very subtle).

It’s feels strange saying this, but hope very few require to read this article to understand these methods.

8 Comments

  • Shouldn't the second code snippet read:

    if (number &lt; 7)

    {

    &nbsp; Console.WriteLine(number);

    }

    else

    {

    &nbsp; break;

    }

    ???

  • The functionality you were expecting is provided by the Where operator. Think of it this way: TakeWhile accepts a condition, and returns all elements while the condition is true, and it stops once the condition fails. It can't (or at least shouldn't) start returning elements again if the condition passes later on, because the original condition was broken; it's incorrect to assume that the condition still has the same meaning once it's been broken.

  • Jeremy, you're right.. code has been corrected.

    Mike, I do know the 'where' operator and the whole blog is because I did read the method description incorrectly.

    Arun

  • thanks. That helped!

  • The actual implementation of TakeWhile method is shown as:
    foreach(var number in numbers)
    {
    if(number < 7)
    Console.WriteLine(number);
    else
    break;
    }

    This is very good to understand. Similarly can you explain SkipWhile method please.

  • I imagine that this:

    int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; &nbsp; foreach(var number in numbers.SkipWhile(n =&gt; n &lt; 7))

    {

    Console.WriteLine(number);

    }

    Would translate to:

    foreach (var number in numbers)

    {

    &nbsp;bool bConditionMet = false;

    &nbsp;if (number &lt; 7 &amp;&amp; bConditionMet == false)

    &nbsp;{

    &nbsp; &nbsp; //skip this number while number &lt; 7

    &nbsp;}

    &nbsp;else

    &nbsp;{

    &nbsp; &nbsp;bConditionMet=true;

    &nbsp; &nbsp;//bConditionMet ensures the remaining items are included.

    &nbsp; &nbsp;Console.WriteLine(number);

    &nbsp;}

    }

  • Thank for the post. Really helpful.

  • You can use this code as below.

    1: int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

    2:

    3: foreach(var number in numbers.Where(n => n < 7))

    4: {

    5: Console.WriteLine(number);

    6: }

    Hope this help

    Thanks,
    Phuong Le.

Comments have been disabled for this content.