Какой лучший способ сделать обратный цикл в C / C # / C ++? - PullRequest
90 голосов
/ 09 ноября 2008

Мне нужно переместиться назад через массив, поэтому у меня есть такой код:

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

Есть ли лучший способ сделать это?

Обновление: я надеялся, что, возможно, в C # был какой-то встроенный механизм для этого, например:

foreachbackwards (int i in myArray)
{
    // so easy
}

Обновление 2: есть лучшие способы. Руна получает приз с:

for (int i = myArray.Length; i-- > 0; )
{    
    //do something
}
//or
for (int i = myArray.Length; i --> 0; )
{
    // do something
}

, который выглядит еще лучше в обычном C (благодаря Twotymz):

for (int i = lengthOfArray; i--; )
{    
    //do something
}

Ответы [ 15 ]

1 голос
/ 15 декабря 2008
// this is how I always do it
for (i = n; --i >= 0;){
   ...
}
0 голосов
/ 09 ноября 2008

Я не уверен, что вижу, почему любая из альтернатив лучше, если доброта включает в себя ясность или ремонтопригодность.

0 голосов
/ 09 ноября 2008

Я бы использовал код в исходном вопросе, но если бы вы действительно хотели использовать foreach и иметь целочисленный индекс в C #:

foreach (int i in Enumerable.Range(0, myArray.Length).Reverse())
{
    myArray[i] = 42; 
}
0 голосов
/ 09 ноября 2008

ПРИМЕЧАНИЕ. Этот пост оказался гораздо более подробным и поэтому не по теме, я прошу прощения.

При этом мои коллеги читают его и верят, что это «где-то». Эта тема не место. Буду признателен за ваши отзывы о том, куда это должно пойти (я новичок на сайте).


В любом случае, это версия C # в .NET 3.5, которая удивительна тем, что работает на любом типе коллекции с использованием определенной семантики. Это показатель по умолчанию (повторное использование!), А не минимизация производительности или цикла ЦП в наиболее распространенном сценарии разработки, хотя, похоже, этого никогда не происходит в реальном мире (преждевременная оптимизация).

*** Метод расширения, работающий над любым типом коллекции и принимающий делегат действия, ожидающий одно значение типа, все выполняются для каждого элемента в обратном порядке **

Требуется 3,5:

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

Старые версии .NET или вы хотите лучше понять внутреннюю среду Linq? Читайте дальше .. Или нет ..

ПРЕДПОЛОЖЕНИЕ: В системе типов .NET тип Array наследуется от интерфейса IEnumerable (не от общего IEnumerable, а только от IEnumerable).

Это все, что вам нужно для перебора от начала до конца, однако вы хотите двигаться в противоположном направлении. Поскольку IEnumerable работает с массивом типа 'object', допустим любой тип,

КРИТИЧЕСКИЕ ИЗМЕРЕНИЯ: Мы предполагаем, что если вы можете обработать любую последовательность в обратном порядке, которая «лучше», чем возможность делать это только на целых числах.

Решение a для .NET CLR 2.0-3.0:

Описание: Мы примем любой реализующий экземпляр IEnumerable с мандатом, что каждый содержащийся в нем экземпляр относится к одному типу. Поэтому, если мы получим массив, весь массив содержит экземпляры типа X. Если любые другие экземпляры относятся к типу! = X, выдается исключение:

Одноразовая услуга:

открытый класс 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] открытый класс 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 голосов
/ 09 ноября 2008

Я попытаюсь ответить на свой вопрос здесь, но мне это тоже не очень нравится:

for (int i = 0; i < myArray.Length; i++)
{
    int iBackwards = myArray.Length - 1 - i; // ugh
    myArray[iBackwards] = 666;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...