12

Is there anyway to foreach through a list from the end to the beginning rather than the beginning to then end (preferably without reordering the list).

sooprise
  • 22,657
  • 67
  • 188
  • 276

8 Answers8

41
using System.Linq;

foreach(var item in source.Reverse())
{
    ...
}

Edit: There is one more step if you are dealing specifically with a List<T>. That class defines its own Reverse method whose signature is not the same as the Enumerable.Reverse extension method. In that case, you need to "lift" the variable reference to IEnumerable<T>:

using System.Linq;

foreach(var item in list.AsEnumerable().Reverse())
{
    ...
}
Bryan Watts
  • 44,911
  • 16
  • 83
  • 88
  • 2
    Note that this will create another list and use twice the memory, so for large lists you will probably want to use a different strategy. But in general this would be the best way to approach it. – drharris Jul 23 '10 at 17:50
  • @Fredou: you are right, the compiler would complain. For `List` you would have to do `source.AsEnumerable().Reverse()`. – Bryan Watts Jul 23 '10 at 17:52
  • @Fredou: I took the OP's reference to "list" as an abstract notion which maps to `IEnumerable<>`. If the question is changed to refer specifically to `List`, I will change my answer :-) – Bryan Watts Jul 23 '10 at 17:55
  • @Bryan Watts, maybe, maybe you can just add under the current answer a little note about list :-) – Fredou Jul 23 '10 at 17:59
  • @Fredou: there is one, the comments! Haha seriously though I'll add a footnote. – Bryan Watts Jul 23 '10 at 18:08
  • @Bryan Watts, I removed my comments :-) and +1 – Fredou Jul 23 '10 at 18:59
  • Following on what @drharris said: if one passes in an enumerable that lacks an optimized implementation of `Reverse`, the default implementation will have no choice but to stack the elements until all have been supplied - using twice the storage as he said. I suspect Bryan's "fix" of `list.AsEnumerable().Reverse` also does that. Needs investigation, before using for a large collection. I am hoping one can override the IEnumerable default, in custom classes. – ToolmakerSteve Mar 02 '17 at 20:57
  • ... So on modern .NET, which has "yield return", [Jon Skeet's answer](http://stackoverflow.com/a/1211626/199364) is preferable for any IList, as it avoids the internal buffering that IEnumerable.Reverse has to do. – ToolmakerSteve Mar 03 '17 at 00:58
9

you could use a regular for loop, start at the end and decrement, instead of starting at the top and incrementing.

something like:

for(int i=foo.lenth; i != 0; i--)
{
do stuff
}
Jim
  • 3,425
  • 9
  • 32
  • 49
  • 1
    Partial truth. You can only use indexing if the collection is indexable (implements IList or provides an indexer member). foreach works on anything that implements IEnumerable and IEnumerable does not provide indexing. – Tergiver Jul 23 '10 at 17:52
  • 1
    It's technically not a foreach, but I like this solution as it doesn't involve the creation of another memory structure. Unfortunately it will not work if the enumeration doesn't have a consistent indexer to decrement. – chilltemp Jul 23 '10 at 17:56
3

You probably don't want to do anything complicated, so I would suggest just using a for loop.

However, if it were somehow a requirement, you can certainly implement your own iterators for custom list iteration behavior.

womp
  • 115,835
  • 26
  • 236
  • 269
2

It depends on what you mean by list.

  • List<T> ? No, unless you use Linq and it's Reverse() function.
  • Your custom collection? Easily, just implement IEnumerator like you want.
Andrey Taptunov
  • 9,367
  • 5
  • 31
  • 44
1

Error checking ommitted for clarity. Use a custom implementation of IEnumerable and IEnumerator. This will avoid unnecessary copying.

using System;
using System.Collections.Generic;

namespace ConsoleApplication3
{
    class ReversedEnumerator : IEnumerator<int>
    {
        List<int> v;
        int index;

        public ReversedEnumerator(List<int> v) {
            this.v = v;
            this.index = v.Count;
        }

        public int Current
        {
            get { return v[index]; }
        }

        public void Dispose()
        {
        }

        object System.Collections.IEnumerator.Current
        {
            get { return v[index]; }
        }

        public bool MoveNext()
        {
            return --index >= 0;
        }

        public void Reset()
        {
            index = this.v.Count;
        }
    }

    class EnumeratorStub : IEnumerable<int>
    {
        List<int> v;

        public EnumeratorStub(List<int> v)
        {
            this.v = v;
        }

        public IEnumerator<int> GetEnumerator()
        {
            return new ReversedEnumerator(v);
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return new ReversedEnumerator(v);
        }

    }

    class Program
    {
        static EnumeratorStub Reverse(List<int> v)
        {
            return new EnumeratorStub(v);
        }

        static void Main(string[] args)
        {
            List<int> v = new List<int>();
            v.Add(1);
            v.Add(2);
            v.Add(3);

            foreach (int item in Reverse(v))
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

I would recommend to refactor the code sample to use generics. That way you could use this for any container type.

Jorge Ferreira
  • 96,051
  • 25
  • 122
  • 132
1
IList<String> strList = new IList<String>();
strList.Add("A");
strList.Add("B");
strList.Add("C");

for (int i = strList.Count-1; i>=0;i--)
{
    Console.WriteLine(strList[i]);
}

not tried but should work.

Tiju John
  • 933
  • 11
  • 28
0

not c# but you can do it too :-)

    Dim a As New List(Of Integer)
    a.Add(1)
    a.Add(2)
    a.Add(3)

    For Each i In a.AsEnumerable.Reverse
        Debug.Print(i)

    Next
Fredou
  • 19,848
  • 10
  • 58
  • 113
0

You can construct your list as a stack and then iterate over the stack:

Stack<char> stack = new Stack<char>();

//Add items...
        
foreach(var item in stack)
{
    ...
}
Jgonzalez731
  • 343
  • 1
  • 3
  • 7