Linq对象中跳过和获取的表现

时间:2016-02-15 13:38:31

标签: c# performance linq paging

“搜索”跳过“和”获取“功能的替代功能”

链接中的1个说“每次你调用Skip()时都必须从头开始迭代你的集合,以便跳过你想要的元素数量,从而在循环中给出一个循环(n2行为)”

结论:对于大型集合,请勿使用Skip and Take。找到另一种方法来迭代你的收藏并划分它。

为了访问大量收藏中的最后一页数据,您能否建议我们采用Skip and Take方法以外的方式?

3 个答案:

答案 0 :(得分:2)

查看Skip的{​​{3}},您可以看到它列举了所有项目,甚至超过了您要跳过的前n项。 但这很奇怪,因为有几种LINQ方法对集合进行了优化,例如CountLast
Skip显然没有。

如果你有一个数组或IList<T>,你可以使用索引器来真正跳过它们:

for (int i = skipStartIndex; i < list.Count; i++) {
    yield return list[i];
}

答案 1 :(得分:1)

在内部,这是非常正确的:

private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
  using (IEnumerator<TSource> enumerator = source.GetEnumerator())
  {
    while (count > 0 && enumerator.MoveNext())
      --count;
    if (count <= 0)
    {
      while (enumerator.MoveNext())
        yield return enumerator.Current;
    }
  }
}

如果您想跳过IEnumerable<T>,那么它可以正常工作。除了枚举之外没有其他方法可以获取特定元素。但您可以在IReadOnlyList<T>IList<T>上编写自己的扩展方法(如果此接口在用于元素的集合中实现)。

public static class IReadOnlyListExtensions
{
    public static IEnumerable<T> Skip<T>(this IReadOnlyList<T> collection, int count)
    {
        if (collection == null)
            return null;

        return ICollectionExtensions.YieldSkip(collection, count);
    }

    private static IEnumerable<T> YieldSkip<T>(IReadOnlyList<T> collection, int count)
    {
        for (int index = count; index < collection.Count; index++)
        {
            yield return collection[index];
        }
    }
}

此外,您可以为IEnumerable<T>实施它,但请在内部进行优化:

if (collection is IReadOnlyList<T>)
{
    // do optimized skip
}

在Linq源代码中使用了很多这样的解决方案(但不幸的是Skip中没有)。

答案 2 :(得分:0)

取决于您的实现,但是为此目的使用索引数组是有意义的。