Paulo Morgado

.NET Development & Architecture

Recent Articles

view all

Events

Projects

Recent Readers

Visitor Locations

Visitor Locations

Disclaimer

The opinions and viewpoints expressed in this site are mine and do not necessarily reflect those of Microsoft, my employer or any community that I belong to. Any code or opinions are offered as is. Products or services mentioned are purchased by me, made available to me by my employer or the manufacturer/vendor which doesn't influence my opinion in any way.

LINQ: Implementing The SkipLastWhile Operator

LINQ Com C#

Following my last posts (>)(>), in this post I’ll introduce the implementation of the SkipLastWhile operator.

The SkipLastWhile returns all but the last contiguous elements from a a sequence that satisfy the specified criteria and is implemented as the SkipLastWhile extension methods:

public static IEnumerable<TSource> SkipLastWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
public static IEnumerable<TSource> SkipLastWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate)

The implementation of these methods is very simple. We start with an empty buffer and buffer every item that satisfies the criteria implemented by a predicate. Whenever an item doesn’t satisfy the criteria, all buffered items are yield, the buffer is cleared and the the item that doesn’t satisfy the criteria is yield:

var buffer = new List<TSource>();

foreach (var item in source)
{
    if (predicate(item))
    {
        buffer.Add(item);
    }
    else
    {
        if (buffer.Count > 0)
        {
            foreach (var bufferedItem in buffer)
            {
                yield return bufferedItem;
            }

            buffer.Clear();
        }

        yield return item;
    }
}

The overload that takes in account the index of the item only differs in the call the predicate that implements the criteria:

var buffer = new List<TSource>();
var idx = 0;

foreach (var item in source)
{
    if (predicate(item, idx++))
    {
        buffer.Add(item);
    }
    else
    {
        if (buffer.Count > 0)
        {
            foreach (var bufferedItem in buffer)
            {
                yield return bufferedItem;
            }

            buffer.Clear();
        }

        yield return item;
    }
}

You can find the complete implementation of this operator (and more) CodePlex project for LINQ utilities and operators: PauloMorgado.Linq

Comments

Juozas Kontvainis said:

If I understand correctly, you reimplemented the TakeWhile() operator with a tweak that it also returns the first item that does not match. Out of sequence 123454321 using predicate x <= 3, your implementation returns 1234. However I would expect it to behave symmetrically to SkipWhile() operator and would expect return value to be 123454.

# October 21, 2010 6:00 AM

DotNetHeaven.Net said:

Thank you for submitting this cool story - Trackback from DotNetHeaven.Net

# October 21, 2010 9:04 AM

Interesting .NET Links - 21st October , 2010 | Tech Blog said:

Pingback from  Interesting .NET Links - 21st October , 2010 | Tech Blog

# October 21, 2010 11:03 AM

Paulo Morgado said:

@Juozas, 123454 is exactly what it is supposed to return.

Isn't that what's being returned?

I just noticed that I had forgotten to check in the latest version, but I suppose the one I hade checked in previously worked.

# October 21, 2010 7:43 PM

Juozas Kontvainis said:

@Paulo, I don't use your library, so I don't know whether actual code works. I'm just trying to point out that the code in this blog post does not seem to do what it's supposed to do.

# October 22, 2010 6:04 AM

Paulo Morgado said:

@Juozas, how come I doesn’t seem to do?

Let’s try it out:

1 – the predicate is true, so it’s buffered

2 – the predicate is true, so it’s buffered

3 – the predicate is true, so it’s buffered

4 – the predicate is false, so all buffered items are yield (1, 2, 3) and the current item (4)

5 – the predicate is false, so all buffered items are yield () and the current item (5)

4 – the predicate is false, so all buffered items are yield () and the current item (4)

3 – the predicate is true, so it’s buffered

2 – the predicate is true, so it’s buffered

1 – the predicate is true, so it’s buffered

The iterator ends without yield the buffered items.

The output will be 1,2,3,4,5 and 4.

Am I missing something?

# October 22, 2010 8:00 PM

Juozas Kontvainis said:

@Paulo, I now see what I somehow managed to miss when I tried to analyze your code :)

Anyway, thanks for the series. It was an interesting read.

# October 26, 2010 4:37 AM

Paulo Morgado said:

@Juozas, I'm glad you found it interesting and thanks for the time you dedicated to it (I'm know to be wrong from time to time :)).

# October 26, 2010 6:58 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)