简体   繁体   English

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

[英]Performance of Skip and Take in Linq to Objects

"Searching for alternative functionalities for "Skip" and "Take" functionalities" “寻找”Skip“和”Take“功能的替代功能”

1 of the link says "Everytime you invoke Skip() it will have to iterate you collection from the beginning in order to skip the number of elements you desire, which gives a loop within a loop (n2 behaviour)" 链接中的1表示“每次调用Skip()时,它都必须从头开始迭代你的集合,以便跳过你想要的元素数量,从而在循环中产生循环(n2行为)”

Conclusion: For large collections, don't use Skip and Take. 结论:对于大型集合,请勿使用Skip和Take。 Find another way to iterate through your collection and divide it. 找到另一种方法来迭代你的收藏并划分它。

In order to access last page data in a huge collection, can you please suggest us a way other than Skip and Take approach? 为了访问庞大的集合中的最后一页数据,您能否建议我们采用除Skip和Take方法之外的其他方式?

Looking at the source for Skip , you can see it enumerates over all the items, even over the first n items you want to skip. 查看Skip源代码 ,您可以看到它枚举所有项目,甚至是您要跳过的前n项。
It's strange though, because several LINQ-methods have optimizations for collections, like Count and Last . 但这很奇怪,因为有几种LINQ方法对集合进行了优化,比如CountLast
Skip apparently does not. Skip显然没有。

If you have an array or IList<T> , you use the indexer to truly skip over them: 如果你有一个数组或IList<T> ,你可以使用索引器来真正跳过它们:

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

Internally it is really correct: 在内部它是非常正确的:

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;
    }
  }
}

If you want to skip for IEnumerable<T> then it works right. 如果你想跳过IEnumerable<T>那么它可以正常工作。 There are no other way except enumeration to get specific element(s). 除了枚举之外没有其他方法可以获取特定元素。 But you can write own extension method on IReadOnlyList<T> or IList<T> (if this interface is implemented in collection used for your elements). 但是您可以在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];
        }
    }
}

In addition you can implement it for IEnumerable<T> but check inside for optimization: 此外,您可以为IEnumerable<T>实现它,但检查内部优化:

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

Such solution is used a lot of where in Linq source code (but not in Skip unfortunately). 在Linq源代码中使用了很多这样的解决方案(但不幸的是没有在Skip中)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM