65.9K
CodeProject 正在变化。 阅读更多。
Home

LINQ:实现 SkipLast 运算符

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2010年10月20日

CPOL

1分钟阅读

viewsIcon

9560

在这篇文章中,我将介绍 SkipLast 运算符的实现。

free hit counters

在上一篇文章之后,在这篇文章中我将介绍 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

© . All rights reserved.