LINQ:实现 TakeLast 运算符。





0/5 (0投票)
TakeLast 运算符从序列的末尾返回指定数量的连续元素,并作为 TakeLast 扩展方法实现。
在上次 文章 之后,在这篇文章中,我将介绍 TakeLast
运算符的实现。
TakeLast
运算符从序列的末尾返回指定数量的连续元素,并作为 TakeLast
扩展方法 实现。
public static IEnumerable<TSource> TakeLast<TSource>(this IEnumerable<TSource> source, int count)
为了实现此运算符,首先我们从 source
序列中缓冲最多 count
个项目到一个数组中,该数组充当循环缓冲区。
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;
}
如果缓冲的项目数量 (numOfItems
) 小于请求的项目数量 (count
),我们只需生成所有缓冲的项目。
if (numOfItems < count)
{
for (idx = 0; idx < numOfItems; idx++)
{
yield return buffer[idx];
}
yield break;
}
接下来,我们循环遍历剩余的项目,以循环方式缓冲它们。
for (end = 0; sourceEnumerator.MoveNext(); end = (end + 1) % count)
{
buffer[end] = sourceEnumerator.Current;
}
最后,我们只需循环遍历缓冲的项目并生成它们。
for (; numOfItems > 0; idx = (idx + 1) % count, numOfItems--)
{
yield return buffer[idx];
}
这里你可以进行两个优化。
第一个显而易见,如果请求的项目数量为 0
(零),我们只需返回一个空序列。
if (count <= 0)
{
return System.Linq.Enumerable.Empty<TSource>();
}
第二个是,如果已知 source
序列实现了 IList<T> 接口。实现此 接口
的对象具有 Count 属性以及对其 项目 的索引访问,这使我们能够优化最终序列的生成。
生成最终序列包括从列表的末尾生成所需的项目数量(或者如果列表包含的项目少于所需数量,则生成所有项目)。
int listCount = list.Count;
for (int i = listCount - ((count < listCount) ? count : listCount); i < listCount; i++)
{
yield return list[i];
}
你可以在 CodePlex 项目中找到此运算符的完整实现(以及更多):LINQ 工具和运算符:PauloMorgado.Linq。