Click here to Skip to main content
Click here to Skip to main content
Technical Blog

LINQ: Implementing The SkipLast Operator

, 20 Oct 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
Following my last post, in this post I’ll introduce the implementation of the SkipLast operator.
free hit countersLINQ With C# (Portuguese)

Following my last post, in this post I’ll introduce the implementation of the SkipLast operator.

The SkipLast operator returns all but a specified number of contiguous elements from the end of a sequence and is implemented as the SkipLast extension method:

public static IEnumerable<TSource> SkipLast<TSource>
	(this IEnumerable<TSource> source, int count)

To implement this operator, first we start by buffering, at most, a count number of items from the source sequence in an array that acts as a circular buffer:

var sourceEnumerator = source.GetEnumerator();
var buffer = new TSource[count];
int idx;

for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++)
{
    buffer[idx] = sourceEnumerator.Current;
}

Next, we iterate over the rest of the items of the source sequence circularly buffering them and yielding the previously buffered item at the same position:

idx = 0;

while (sourceEnumerator.MoveNext())
{
    var item = buffer[idx];

    buffer[idx] = sourceEnumerator.Current;

    idx = (idx + 1) % count;

    yield return item;
}

If the number of items to skip is greater than or equal to the number of items in the source sequence, sourceEnumerator.MoveNext() will return false on the first iteration of the while loop and an empty sequence will be produced.

As with the TakeLast operator, a few optimizations can be made here.

The first is obvious, if the requested number of items is 0 (zero) or lower, we just return an equivalent sequence:

if (count <= 0)
{
    return source.Select(i => i);
}

The second is if the source sequence is known to implement the IList<T> interface. Objects implementing this interface have a Count property and indexed access to its items which allows us to optimize the production of the final sequence.

If the number of items to skip is equal to or greater than the number of items in the source sequence, we just return an empty sequence:

var list = source as IList<TSource>;

if (list != null)
{
    if (count >= list.Count)
    {
        return System.Linq.Enumerable.Empty<TSource>();
    }

    // ...
}

If the number of items in the source sequence is greater than the number of items to skip, producing the final sequence consists of yielding all the items in the source sequence except the last count items:

int returnCount = list.Count - count;

for (int idx = 0; idx < returnCount; idx++)
{
    yield return list[idx];
}

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Paulo Morgado
Software Developer (Senior) Paulo Morgado
Portugal Portugal

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 20 Oct 2010
Article Copyright 2010 by Paulo Morgado
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid