Click here to Skip to main content
12,359,751 members (64,795 online)
Click here to Skip to main content
Add your own
alternative version

Stats

5.7K views
2 bookmarked
Posted

LINQ: Implementing the TakeLast Operator

, 20 Oct 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
The TakeLast operator returns a specified number of contiguous elements from the end of a sequence and is implemented as the TakeLast extension method.
free hit countersLINQ With C# (Portuguese)

Following my last post, in this post I'll introduce the implementation of the TakeLast operator.

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

public static IEnumerable<TSource> TakeLast<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];
var numOfItems = 0;
int end;

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

If the number of buffered items (numOfItems) is less than the requested number of items (count), we just yield all the buffered items:

if (numOfItems < count)
{
    for (idx = 0; idx < numOfItems; idx++)
    {
        yield return buffer[idx];
    }

    yield break;
}

Next, we iterate over the rest of the items circularly buffering them:

for (end = 0; sourceEnumerator.MoveNext(); end = (end + 1) % count)
{
    buffer[end] = sourceEnumerator.Current;
}

And finally, we just iterate over the buffered items and yield them:

for (; numOfItems > 0; idx = (idx + 1) % count, numOfItems--)
{
    yield return buffer[idx];
}

There are two optimizations you can make here.

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

if (count <= 0)
{
    return System.Linq.Enumerable.Empty<TSource>();
}

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.

Producing the final sequence consists of yielding the required number of items from the end of the list (or all of them if the list contains less items than required):

int listCount = list.Count;

for (int i = listCount - ((count < listCount) ? count : listCount); i < listCount; i++)
{
    yield return list[i];
}

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

You may also be interested in...

Comments and Discussions

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