What's the best way to do a backwards loop in C/C#/C++?

后端 未结 14 2597
终归单人心
终归单人心 2020-11-28 01:39

I need to move backwards through an array, so I have code like this:

for (int i = myArray.Length - 1; i >= 0; i--)
{
    // Do something
    myArray[i] =          


        
相关标签:
14条回答
  • 2020-11-28 02:01

    Looks good to me. If the indexer was unsigned (uint etc), you might have to take that into account. Call me lazy, but in that (unsigned) case, I might just use a counter-variable:

    uint pos = arr.Length;
    for(uint i = 0; i < arr.Length ; i++)
    {
        arr[--pos] = 42;
    }
    

    (actually, even here you'd need to be careful of cases like arr.Length = uint.MaxValue... maybe a != somewhere... of course, that is a very unlikely case!)

    0 讨论(0)
  • 2020-11-28 02:01

    In C I like to do this:

    
    int i = myArray.Length;
    while (i--) {
      myArray[i] = 42;
    }
    
    

    C# example added by MusiGenesis:

    {int i = myArray.Length; while (i-- > 0)
    {
        myArray[i] = 42;
    }}
    
    0 讨论(0)
  • 2020-11-28 02:02

    The best way to do that in C++ is probably to use iterator (or better, range) adaptors, which will lazily transform the sequence as it is being traversed.

    Basically,

    vector<value_type> range;
    foreach(value_type v, range | reversed)
        cout << v;
    

    Displays the range "range" (here, it's empty, but i'm fairly sure you can add elements yourself) in reverse order. Of course simply iterating the range is not much use, but passing that new range to algorithms and stuff is pretty cool.

    This mechanism can also be used for much more powerful uses:

    range | transformed(f) | filtered(p) | reversed
    

    Will lazily compute the range "range", where function "f" is applied to all elements, elements for which "p" is not true are removed, and finally the resulting range is reversed.

    Pipe syntax is the most readable IMO, given it's infix. The Boost.Range library update pending review implements this, but it's pretty simple to do it yourself also. It's even more cool with a lambda DSEL to generate the function f and the predicate p in-line.

    0 讨论(0)
  • 2020-11-28 02:03

    While admittedly a bit obscure, I would say that the most typographically pleasing way of doing this is

    for (int i = myArray.Length; i --> 0; )
    {
        //do something
    }
    
    0 讨论(0)
  • 2020-11-28 02:04

    NOTE: This post ended up being far more detailed and therefore off topic, I apologize.

    That being said my peers read it and believe it is valuable 'somewhere'. This thread is not the place. I would appreciate your feedback on where this should go (I am new to the site).


    Anyway this is the C# version in .NET 3.5 which is amazing in that it works on any collection type using the defined semantics. This is a default measure (reuse!) not performance or CPU cycle minimization in most common dev scenario although that never seems to be what happens in the real world (premature optimization).

    *** Extension method working over any collection type and taking an action delegate expecting a single value of the type, all executed over each item in reverse **

    Requres 3.5:

    public static void PerformOverReversed<T>(this IEnumerable<T> sequenceToReverse, Action<T> doForEachReversed)
          {
              foreach (var contextItem in sequenceToReverse.Reverse())
                  doForEachReversed(contextItem);
          }
    

    Older .NET versions or do you want to understand Linq internals better? Read on.. Or not..

    ASSUMPTION: In the .NET type system the Array type inherits from the IEnumerable interface (not the generic IEnumerable only IEnumerable).

    This is all you need to iterate from beginning to end, however you want to move in the opposite direction. As IEnumerable works on Array of type 'object' any type is valid,

    CRITICAL MEASURE: We assume if you can process any sequence in reverse order that is 'better' then only being able to do it on integers.

    Solution a for .NET CLR 2.0-3.0:

    Description: We will accept any IEnumerable implementing instance with the mandate that each instance it contains is of the same type. So if we recieve an array the entire array contains instances of type X. If any other instances are of a type !=X an exception is thrown:

    A singleton service:

    public class ReverserService { private ReverserService() { }

        /// <summary>
        /// Most importantly uses yield command for efficiency
        /// </summary>
        /// <param name="enumerableInstance"></param>
        /// <returns></returns>
        public static IEnumerable ToReveresed(IEnumerable enumerableInstance)
        {
            if (enumerableInstance == null)
            {
                throw new ArgumentNullException("enumerableInstance");
            }
    
            // First we need to move forwarad and create a temp
            // copy of a type that allows us to move backwards
            // We can use ArrayList for this as the concrete
            // type
    
            IList reversedEnumerable = new ArrayList();
            IEnumerator tempEnumerator = enumerableInstance.GetEnumerator();
    
            while (tempEnumerator.MoveNext())
            {
                reversedEnumerable.Add(tempEnumerator.Current);
            }
    
            // Now we do the standard reverse over this using yield to return
            // the result
            // NOTE: This is an immutable result by design. That is 
            // a design goal for this simple question as well as most other set related 
            // requirements, which is why Linq results are immutable for example
            // In fact this is foundational code to understand Linq
    
            for (var i = reversedEnumerable.Count - 1; i >= 0; i--)
            {
                yield return reversedEnumerable[i];
            }
        }
    }
    
    
    
    public static class ExtensionMethods
    {
    
          public static IEnumerable ToReveresed(this IEnumerable enumerableInstance)
          {
              return ReverserService.ToReveresed(enumerableInstance);
          }
     }
    

    [TestFixture] public class Testing123 {

        /// <summary>
        /// .NET 1.1 CLR
        /// </summary>
        [Test]
        public void Tester_fornet_1_dot_1()
        {
            const int initialSize = 1000;
    
            // Create the baseline data
            int[] myArray = new int[initialSize];
    
            for (var i = 0; i < initialSize; i++)
            {
                myArray[i] = i + 1;
            }
    
            IEnumerable _revered = ReverserService.ToReveresed(myArray);
    
            Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
        }
    
        [Test]
        public void tester_why_this_is_good()
        {
    
            ArrayList names = new ArrayList();
            names.Add("Jim");
            names.Add("Bob");
            names.Add("Eric");
            names.Add("Sam");
    
            IEnumerable _revered = ReverserService.ToReveresed(names);
    
            Assert.IsTrue(TestAndGetResult(_revered).Equals("Sam"));
    
    
        }
    
        [Test]
        public void tester_extension_method()
      {
    
            // Extension Methods No Linq (Linq does this for you as I will show)
            var enumerableOfInt = Enumerable.Range(1, 1000);
    
            // Use Extension Method - which simply wraps older clr code
            IEnumerable _revered = enumerableOfInt.ToReveresed();
    
            Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
    
    
        }
    
    
        [Test]
        public void tester_linq_3_dot_5_clr()
        {
    
            // Extension Methods No Linq (Linq does this for you as I will show)
            IEnumerable enumerableOfInt = Enumerable.Range(1, 1000);
    
            // Reverse is Linq (which is are extension methods off IEnumerable<T>
            // Note you must case IEnumerable (non generic) using OfType or Cast
            IEnumerable _revered = enumerableOfInt.Cast<int>().Reverse();
    
            Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
    
    
        }
    
    
    
        [Test]
        public void tester_final_and_recommended_colution()
        {
    
            var enumerableOfInt = Enumerable.Range(1, 1000);
            enumerableOfInt.PerformOverReversed(i => Debug.WriteLine(i));
    
        }
    
    
    
        private static object TestAndGetResult(IEnumerable enumerableIn)
        {
          //  IEnumerable x = ReverserService.ToReveresed(names);
    
            Assert.IsTrue(enumerableIn != null);
            IEnumerator _test = enumerableIn.GetEnumerator();
    
            // Move to first
            Assert.IsTrue(_test.MoveNext());
            return _test.Current;
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:05

    I'm going to try answering my own question here, but I don't really like this, either:

    for (int i = 0; i < myArray.Length; i++)
    {
        int iBackwards = myArray.Length - 1 - i; // ugh
        myArray[iBackwards] = 666;
    }
    
    0 讨论(0)
提交回复
热议问题