Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does IEnumerable<T>.Reverse work?

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?

like image 535
Joan Venge Avatar asked Jun 26 '09 22:06

Joan Venge


People also ask

What is IEnumerable T?

IEnumerable<T> is the base interface for collections in the System. Collections. Generic namespace such as List<T>, Dictionary<TKey,TValue>, and Stack<T> and other generic collections such as ObservableCollection<T> and ConcurrentStack<T>.

How do you reverse a list in C#?

To create a reversed copy of the original list, we can use the Enumerable. Reverse() method. It just creates a new sequence with elements in the reverse order without modifying the underlying list. The following code example reverses a list using the Reverse() method.

Why do we use IEnumerable in C#?

IEnumerable in C# is an interface that defines one method, GetEnumerator which returns an IEnumerator interface. This allows readonly access to a collection then a collection that implements IEnumerable can be used with a for-each statement.


3 Answers

In short, it buffers everything and then walks through it backwards. Not efficient, but then, neither is OrderBy from that perspective.

In LINQ-to-Objects, there are buffering operations (Reverse, OrderBy, GroupBy, etc) and non-buffering operations (Where, Take, Skip, etc).


As an example of a non-buffering Reverse implementation using IList<T>, consider:

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

like image 199
Marc Gravell Avatar answered Nov 15 '22 09:11

Marc Gravell


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.

For more information, check out System.Linq.Buffer<TElement> in Reflector.

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>.

like image 32
Levi Avatar answered Nov 15 '22 11:11

Levi


it loads all items to memory and then steps through them (backwards). this is far less efficient.

like image 28
Matt Lacey Avatar answered Nov 15 '22 11:11

Matt Lacey