Possible to iterate backwards through a foreach?

前端 未结 11 2134
无人及你
无人及你 2020-11-27 03:54

I know I could use a for statement and achieve the same effect, but can I loop backwards through a foreach loop in C#?

相关标签:
11条回答
  • 2020-11-27 04:39

    This works pretty well

    List<string> list = new List<string>();
    
    list.Add("Hello");
    list.Add("Who");
    list.Add("Are");
    list.Add("You");
    
    foreach (String s in list)
    {
        Console.WriteLine(list[list.Count - list.IndexOf(s) - 1]);
    }
    
    0 讨论(0)
  • 2020-11-27 04:42

    If you are on .NET 3.5 you can do this:

    IEnumerable<int> enumerableThing = ...;
    foreach (var x in enumerableThing.Reverse())
    

    It isn't very efficient as it has to basically go through the enumerator forwards putting everything on a stack then pops everything back out in reverse order.

    If you have a directly-indexable collection (e.g. IList) you should definitely use a for loop instead.

    If you are on .NET 2.0 and cannot use a for loop (i.e. you just have an IEnumerable) then you will just have to write your own Reverse function. This should work:

    static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
    {
        return new Stack<T>(input);
    }
    

    This relies on some behaviour which is perhaps not that obvious. When you pass in an IEnumerable to the stack constructor it will iterate through it and push the items onto the stack. When you then iterate through the stack it pops things back out in reverse order.

    This and the .NET 3.5 Reverse() extension method will obviously blow up if you feed it an IEnumerable which never stops returning items.

    0 讨论(0)
  • 2020-11-27 04:42

    Before using foreach for iteration, reverse the list by the reverse method:

        myList.Reverse();
        foreach( List listItem in myList)
        {
           Console.WriteLine(listItem);
        }
    
    0 讨论(0)
  • 2020-11-27 04:46

    Elaborateling slighty on the nice answer by Jon Skeet, this could be versatile:

    public static IEnumerable<T> Directional<T>(this IList<T> items, bool Forwards) {
        if (Forwards) foreach (T item in items) yield return item;
        else for (int i = items.Count-1; 0<=i; i--) yield return items[i];
    }
    

    And then use as

    foreach (var item in myList.Directional(forwardsCondition)) {
        .
        .
    }
    
    0 讨论(0)
  • 2020-11-27 04:47

    Sometimes you don't have the luxury of indexing, or perhaps you want to reverse the results of a Linq query, or maybe you don't want to modify the source collection, if any of these are true, Linq can help you.

    A Linq extension method using anonymous types with Linq Select to provide a sorting key for Linq OrderByDescending;

        public static IEnumerable<T> Invert<T>(this IEnumerable<T> source)
        {
            var transform = source.Select(
                (o, i) => new
                {
                    Index = i,
                    Object = o
                });
    
            return transform.OrderByDescending(o => o.Index)
                            .Select(o => o.Object);
        }
    

    Usage:

        var eable = new[]{ "a", "b", "c" };
    
        foreach(var o in eable.Invert())
        {
            Console.WriteLine(o);
        }
    
        // "c", "b", "a"
    

    It is named "Invert" because it is synonymous with "Reverse" and enables disambiguation with the List Reverse implementation.

    It is possible to reverse certain ranges of a collection too, since Int32.MinValue and Int32.MaxValue are out of the range of any kind of collection index, we can leverage them for the ordering process; if an element index is below the given range, it is assigned Int32.MaxValue so that its order doesn't change when using OrderByDescending, similarly, elements at an index greater than the given range, will be assigned Int32.MinValue, so that they appear to the end of the ordering process. All elements within the given range are assigned their normal index and are reversed accordingly.

        public static IEnumerable<T> Invert<T>(this IEnumerable<T> source, int index, int count)
        {
            var transform = source.Select(
                (o, i) => new
                {
                    Index = i < index ? Int32.MaxValue : i >= index + count ? Int32.MinValue : i,
                    Object = o
                });
    
            return transform.OrderByDescending(o => o.Index)
                            .Select(o => o.Object);
        }
    

    Usage:

        var eable = new[]{ "a", "b", "c", "d" };
    
        foreach(var o in eable.Invert(1, 2))
        {
            Console.WriteLine(o);
        }
    
        // "a", "c", "b", "d"
    

    I'm not sure of the performance hits of these Linq implementations versus using a temporary List to wrap a collection for reversing.


    At time of writing, I was not aware of Linq's own Reverse implementation, still, it was fun working this out. https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx

    0 讨论(0)
提交回复
热议问题