0

After making a search at the Google, I found this discussion:

Possible to iterate backwards through a foreach?

But in the answers there is used extension method .Reverse(). With reverse, the list of objects, for ie. List of Strings, wtill be reversed first, and foreach doesn't reverse the list with my understoodment? If I got list "Cat", "Dog", and use .Reverse() -method, the list will be "Dog", "Cat", and foreach starts from the 0 element till the lenght-1 -element and that's what I'm not looking for. I would want to know, if there was any way to reverse foreach iteration order, to start from lenght-1 down to 0.

Community
  • 1
  • 1
Jere_Sumell
  • 543
  • 1
  • 4
  • 8
  • If you really have an `Array` why care for `foreach`? Good old `for` will do it good'nuff and probably fast than any other way, too. – TaW Sep 27 '14 at 14:50
  • Why don't you write your own (extension) method? What you want is not very common and usual to be in standard libraries. – Alireza Sep 27 '14 at 14:50

3 Answers3

2

if there was any way to reverse foreach iteration order, to start from length-1 down to 0

Not for a List<T>. The implementation of GetEnumerator() returns an enumerator that enumerates from beginning to end - there's no way to override that.

With a custom collection, then you'd just have to use a different enumerator that could go backwards, but there's no way to override the implementation that List<T> uses.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
1

The Reverse method will copy the list first:

public static IEnumerable<TSource> Reverse<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source"); 
    return ReverseIterator<TSource>(source);
}

static IEnumerable<TSource> ReverseIterator<TSource>(IEnumerable<TSource> source) { 
    Buffer<TSource> buffer = new Buffer<TSource>(source);
    for (int i = buffer.count - 1; i >= 0; i--) yield return buffer.items[i]; 
} 

But you can do an extension method yourself:

public static IEnumerable<TSource> Backwards<TSource>(this IList<TSource> source) {
    for (var i = source.Count - 1; i >= 0; --i)
        yield return source[i];
}

And then use it like that:

foreach (var item in array.Backwards())
    Console.WriteLine(item); // Or whatever else

Or, of course, you could just do the equivalent:

for (var i = array.Length - 1; i >= 0; --i)
    Console.WriteLine(array[i]); // Or whatever else
Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
  • @DStanley This is unfortunate, but it *does* a copy even in this case. See the source code in my answer. And `Buffer` [copies the list](http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs#2548). – Lucas Trzesniewski Sep 27 '14 at 14:56
1

You can implement an enumerator that iterates though a list backwards. That way you can use foreach without changing the original list or creating a copy of it.

public class ReverseEnumerator<T> : IEnumerator<T> {

  private IList<T> _list;
  private int _index;
  private T _current;

  public ReverseEnumerator(IList<T> list) {
    _list = list;
    Reset();
  }

  public IEnumerator<T> GetEnumerator() {
    return this;
  }

  public T Current {
    get {
      if (_index < 0 && _index >= _list.Count) throw new InvalidOperationException("Enumeration has not started. Call MoveNext.");
      return _current;
    }
  }

  public void Dispose() { }

  object IEnumerator.Current { get { return Current; } }

  public bool MoveNext() {
    bool ok = --_index >= 0;
    if (ok) _current = _list[_index];
    return ok;
  }

  public void Reset() {
    _index = _list.Count;
  }

}

Usage example:

int[] a = { 1, 2, 3, 4, 5 };

foreach (int x in new ReverseEnumerator<int>(a)) {
  Console.WriteLine(x);
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • You might want to do it as a `ICollection` (or even a `IReadOnlyCollection` if this is .NET 4.5) instead of a `IList` it would be compatible with more things and you still have access to the indexer. – Scott Chamberlain Sep 27 '14 at 16:50
  • @ScottChamberlain: How do you access items by index in an `ICollection`? – Guffa Sep 27 '14 at 17:42
  • Huh, I would have put money on the fact that ICollection exposed a Index property. Sorry. – Scott Chamberlain Sep 27 '14 at 17:44