tags:

views:

165

answers:

7

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

+11  A: 
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
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
@Fredou: you are right, the compiler would complain. For `List<T>` you would have to do `source.AsEnumerable().Reverse()`.
Bryan Watts
@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<T>`, I will change my answer :-)
Bryan Watts
@Bryan Watts, maybe, maybe you can just add under the current answer a little note about list<t> :-)
Fredou
@Fredou: there is one, the comments! Haha seriously though I'll add a footnote.
Bryan Watts
@Bryan Watts, I removed my comments :-) and +1
Fredou
+6  A: 

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
@Jim: 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
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
Question did specify a list
MaLio
+3  A: 

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
A: 

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
+2  A: 

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.
Andrei Taptunov
A: 

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.

smink
A: 
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