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.

Published Thursday, April 08, 2010 11:14 PM by nmarun
Filed under: ,

Comments

# re: LINQ – TakeWhile and SkipWhile methods

Thursday, April 08, 2010 1:13 PM by Jeremy Likness

Shouldn't the second code snippet read:

if (number < 7)

{

  Console.WriteLine(number);

}

else

{

  break;

}

???

# re: LINQ – TakeWhile and SkipWhile methods

Thursday, April 08, 2010 1:20 PM by Mike Strobel

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.

# re: LINQ – TakeWhile and SkipWhile methods

Thursday, April 08, 2010 1:49 PM by nmarun

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

# re: LINQ – TakeWhile and SkipWhile methods

Monday, August 16, 2010 3:58 PM by andiih

thanks. That helped!

# re: LINQ – TakeWhile and SkipWhile methods

Tuesday, March 15, 2011 7:39 AM by firoj2005

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.

# re: LINQ – TakeWhile and SkipWhile methods

Monday, March 21, 2011 12:42 PM by Tim L

I imagine that this:

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

{

Console.WriteLine(number);

}

Would translate to:

foreach (var number in numbers)

{

 bool bConditionMet = false;

 if (number < 7 && bConditionMet == false)

 {

    //skip this number while number < 7

 }

 else

 {

   bConditionMet=true;

   //bConditionMet ensures the remaining items are included.

   Console.WriteLine(number);

 }

}

Leave a Comment

(required) 
(required) 
(optional)
(required)