C# IEnumerable<T>.Reverse 如何工作?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1051612/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does IEnumerable<T>.Reverse work?
提问by Joan Venge
I am checking out the code in the reflector, but I haven't yet found out how it can enumerate through a collection backwards?
我正在检查反射器中的代码,但我还没有发现它如何向后枚举集合?
Since there is no count information, and enumeration always starts from the "start" of the collection, right?
既然没有计数信息,枚举总是从集合的“开始”开始,对吗?
Is it a drawback in the .NET framework? Is the cost higher than regular enumeration?
它是 .NET 框架的一个缺点吗?成本是否高于常规枚举?
采纳答案by Marc Gravell
In short, it buffers everything and then walks through it backwards. Not efficient, but then, neither is OrderBy from that perspective.
简而言之,它缓冲所有内容,然后向后遍历。效率不高,但从这个角度来看,OrderBy 也不是。
In LINQ-to-Objects, there are buffering operations (Reverse, OrderBy, GroupBy, etc) and non-buffering operations (Where, Take, Skip, etc).
在 LINQ-to-Objects 中,有缓冲操作(Reverse、OrderBy、GroupBy 等)和非缓冲操作(Where、Take、Skip 等)。
As an example of a non-buffering Reverse
implementation using IList<T>
, consider:
作为使用 的非缓冲Reverse
实现的示例IList<T>
,请考虑:
public static IEnumerable<T> Reverse<T>(this IList<T> list) {
for (int i = list.Count - 1; i >= 0; i--) {
yield return list[i];
}
}
Note that this is still a little susceptible to bugs if you mutate the list while iterating it... so don't do that ;-p
请注意,如果您在迭代列表时改变列表,这仍然有点容易受到错误的影响......所以不要这样做;-p
回答by Levi
It works by copying the underlying IEnumerable<T> to an array, then enumerating over that array backward. If the underlying IEnumerable<T> implements ICollection<T> (like T[], List<T>, etc.), then the copy step is skipped and the enumerator just iterates over the underlying collection directly.
它的工作原理是将底层 IEnumerable<T> 复制到一个数组,然后向后枚举该数组。 如果底层 IEnumerable<T> 实现了 ICollection<T>(如 T[]、List<T> 等),则跳过复制步骤,枚举器直接遍历底层集合。
For more information, check out System.Linq.Buffer<TElement> in Reflector.
有关更多信息,请查看 Reflector 中的 System.Linq.Buffer<TElement>。
Edit: The underlying collection is always copied, even if it's an ICollection<TElement>. This prevents changes in the underlying collection from being propagated by the Buffer<TElement>.
编辑:底层集合总是被复制,即使它是一个 ICollection<TElement>。这可以防止 Buffer<TElement> 传播底层集合中的更改。
回答by Matt Lacey
it loads all items to memory and then steps through them (backwards). this is far less efficient.
它将所有项目加载到内存中,然后逐步遍历它们(向后)。这效率要低得多。
回答by mamu
Edit: Opps, wrote wrong test for reverse, my apology for wrong answer. It does buffer after correcting test(using enumerable returned by Reverse())
编辑:Opps,为反向写了错误的测试,我为错误的答案道歉。它在校正测试后进行缓冲(使用 Reverse() 返回的可枚举)
Looks like Reverse extension method only works when collection is populated. While using yield return it does not do anything.
看起来反向扩展方法仅在填充集合时才有效。使用 yield return 它不做任何事情。
Ran into problem using reverse thought it must buffer for it to work, found it does not work with yield. It just go pass it and don't do anything. below is my test code.
遇到问题使用反向认为它必须缓冲才能工作,发现它不适用于产量。它只是通过它而不做任何事情。下面是我的测试代码。
[TestMethod]
public void loopTest()
{
var series = this.GetSeries();
series.Reverse();
foreach (var l in series)
{
Debug.WriteLine(l);
}
}
private IEnumerable<long> GetSeries()
{
var series = new List<long>() { 1, 2, 3, 4 };
foreach (var entry in series)
{
Debug.WriteLine(entry);
yield return entry;
}
}
Reverse do not call GetSeries function at all, all buffer talks in this forum looks from thin air.
反向根本不调用 GetSeries 函数,本论坛所有缓冲区讨论都是凭空而来的。