跳跃的性能(和类似的功能,喜欢拍摄) [英] Performance of Skip (and similar functions, like Take)
问题描述
我只是看看源$ C $ c中的跳过
/ 以
的扩展方法.NET框架(在的IEnumerable< T>
键入),发现内部实现与的GetEnumerator
方法工作
I just had a look at the source code of the Skip
/Take
extension methods of the .NET Framework (on the IEnumerable<T>
type) and found that the internal implementation is working with the GetEnumerator
method:
// .NET framework
public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> source, int count)
{
if (source == null) throw Error.ArgumentNull("source");
return SkipIterator<TSource>(source, count);
}
static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
{
using (IEnumerator<TSource> e = source.GetEnumerator())
{
while (count > 0 && e.MoveNext()) count--;
if (count <= 0)
{
while (e.MoveNext()) yield return e.Current;
}
}
}
假设我有一个的IEnumerable&LT; T&GT;
1000元(基本类型是列表&LT; T&GT;
) 。如果我做list.Skip(990)。取(10)会发生什么?它会遍历througt走过去的十年前的990第一要素? (这是我的理解)。如果是的话,那么我不明白为什么微软没有实现这样的跳过
方法:
Suppose that I have an IEnumerable<T>
with 1000 elements (underlying type is List<T>
). What happens if I'm doing list.Skip(990).Take(10) ? Will it iterate througt the 990 first elements before taking the last ten? (this is how I understand it). If yes, then I don't understand why Microsoft didn't implement the Skip
method like this:
// Not tested... just to show the idea
public static IEnumerable<T> Skip<T>(this IEnumerable<T> source, int count)
{
if (source is IList<T>)
{
IList<T> list = (IList<T>)source;
for (int i = count; i < list.Count; i++)
{
yield return list[i];
}
}
else if (source is IList)
{
IList list = (IList)source;
for (int i = count; i < list.Count; i++)
{
yield return (T)list[i];
}
}
else
{
// .NET framework
using (IEnumerator<T> e = source.GetEnumerator())
{
while (count > 0 && e.MoveNext()) count--;
if (count <= 0)
{
while (e.MoveNext()) yield return e.Current;
}
}
}
}
在事实上,他们这样做的计数
方法,例如...
In fact, they did that for the Count
method for example...
// .NET Framework...
public static int Count<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw Error.ArgumentNull("source");
ICollection<TSource> collectionoft = source as ICollection<TSource>;
if (collectionoft != null) return collectionoft.Count;
ICollection collection = source as ICollection;
if (collection != null) return collection.Count;
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
checked
{
while (e.MoveNext()) count++;
}
}
return count;
}
所以,有什么原因呢?
So what's the reason?
推荐答案
在乔恩斯基特的优秀教程重新实施<一个href=\"https://msmvps.com/blogs/jon_skeet/archive/2011/01/02/reimplementing-linq-to-objects-part-23-take-skip-takewhile-skipwhile.aspx\">Linq,他讨论了(暂时的)这个问题了:
In Jon Skeet's excellent tutorial re-implementing Linq, he discusses (briefly) that very question:
尽管大多数这些操作不能合理地优化,它
将是有意义的优化跳过当源实现IList。
我们可以跳过跳绳,可以这么说,并直接进入
适当的索引。这不会发现其中源是事实
迭代,这可能是一个原因之间修改它不是
在该框架就我所知实现的。
Although most of these operations can't be sensibly optimized, it would make sense to optimize Skip when the source implements IList. We can skip the skipping, so to speak, and go straight to the appropriate index. This wouldn't spot the case where the source was modified between iterations, which may be one reason it's not implemented in the framework as far as I'm aware.
这似乎是一个合理的理由推迟了优化,但我同意,具体的情况下,它可能是值得做的优化,如果你能保证你的源不能/不会被修改。
That seems like a reasonable reason to hold off on that optimization, but I agree that for specific cases, it may be worthwhile to make that optimization if you can guarantee your source can't/won't be modified.
这篇关于跳跃的性能(和类似的功能,喜欢拍摄)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!