LINQ:实现 SkipLast 运算符





0/5 (0投票)
在这篇文章中,我将介绍 SkipLast 运算符的实现。
在上一篇文章之后,在这篇文章中我将介绍 SkipLast
运算符的实现。
SkipLast
运算符返回序列末尾指定数量的连续元素之外的所有元素,并作为 SkipLast
扩展方法实现。
public static IEnumerable<TSource> SkipLast<TSource>
(this IEnumerable<TSource> source, int count)
为了实现这个运算符,首先我们从 source
序列中缓冲最多 count
个项目到一个数组中,该数组充当循环缓冲区。
var sourceEnumerator = source.GetEnumerator();
var buffer = new TSource[count];
int idx;
for (idx = 0; (idx < count) && sourceEnumerator.MoveNext(); idx++)
{
buffer[idx] = sourceEnumerator.Current;
}
接下来,我们循环遍历 source
序列的其余项目,以循环方式缓冲它们,并在相同位置产生先前缓冲的项目。
idx = 0;
while (sourceEnumerator.MoveNext())
{
var item = buffer[idx];
buffer[idx] = sourceEnumerator.Current;
idx = (idx + 1) % count;
yield return item;
}
如果要跳过的项目数大于或等于 source
序列中的项目数,则 sourceEnumerator.MoveNext()
在 while
循环的第一次迭代时将返回 false
,并且将生成一个空序列。
与 TakeLast
运算符一样,可以进行一些优化。
第一个显而易见,如果请求的项目数为 0
(零)或更少,我们只需返回一个等效的序列。
if (count <= 0)
{
return source.Select(i => i);
}
第二个是,如果已知 source
序列实现了 IList<T> 接口
。实现此 接口
的对象具有 Count 属性以及对其 项目的索引访问,这使我们能够优化最终序列的生成。
如果要跳过的项目数等于或大于 source
序列中的项目数,我们只需返回一个空序列。
var list = source as IList<TSource>;
if (list != null)
{
if (count >= list.Count)
{
return System.Linq.Enumerable.Empty<TSource>();
}
// ...
}
如果 source
序列中的项目数大于要跳过的项目数,则生成最终序列包括产生 source
序列中的所有项目,除了最后的 count
个项目。
int returnCount = list.Count - count;
for (int idx = 0; idx < returnCount; idx++)
{
yield return list[idx];
}
您可以在 CodePlex 项目中找到此运算符(以及更多)的完整实现,用于 LINQ 工具和运算符:PauloMorgado.Linq。