Что лучший способ состоит в том, чтобы сделать назад цикл в C/C#/C ++?

Когда объект генератора собирает мусор в конце вашей программы, его метод close() вызывается, и это вызывает исключение GeneratorExit внутри генератора. Обычно это не улавливается и приводит к выходу генератора.

Поскольку вы обнаруживаете исключение и получаете другое значение, это вызывает RuntimeError. Если вы поймаете исключение GeneratorExit, вам нужно либо сделать ререйз, либо выйти из функции, не принося ничего другого.

91
задан MusiGenesis 14 November 2008 в 03:33
поделиться

13 ответов

В то время как по общему признанию немного неясный, я сказал бы, что наиболее типографским способом приятный способ сделать это

for (int i = myArray.Length; i --> 0; )
{
    //do something
}
133
ответ дан MusiGenesis 5 November 2019 в 13:50
поделиться

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

for (int i = 0; i < myArray.Length; i++)
{
    int iBackwards = myArray.Length - 1 - i; // ugh
    myArray[iBackwards] = 666;
}
-1
ответ дан MusiGenesis 5 November 2019 в 13:50
поделиться

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

0
ответ дан dkretz 5 November 2019 в 13:50
поделиться

Лучший способ сделать это в C++ должно, вероятно, использовать итератор (или лучше, диапазон) адаптеры, которые лениво преобразуют последовательность, поскольку это пересекается.

В основном,

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

Дисплеи диапазон "диапазон" (здесь, это пусто, но я абсолютно уверен, что можно добавить элементы сами), в обратном порядке. Конечно, просто итерация диапазона не полезна, но передача, что новый диапазон к алгоритмам и материалу довольно прохладен.

Этот механизм может также использоваться для намного более мощного использования:

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

лениво вычислит диапазон "диапазон", где функция "f" применяется ко всем элементам, удалены элементы, для которых "p" не верен, и наконец получающийся диапазон инвертируется.

синтаксис Канала является самым читаемым IMO, учитывая он - инфикс. Повышение. Обновление библиотеки диапазона, ожидающее, обзор реализует это, но довольно просто сделать это самостоятельно также. С лямбдой DSEL еще более здорово генерировать функцию f и предикат p встроенный.

3
ответ дан 5 November 2019 в 13:50
поделиться
// this is how I always do it
for (i = n; --i >= 0;){
   ...
}
1
ответ дан Mike Dunlavey 5 November 2019 в 13:50
поделиться

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

foreach (int i in Enumerable.Range(0, myArray.Length).Reverse())
{
    myArray[i] = 42; 
}
0
ответ дан xyz 5 November 2019 в 13:50
поделиться

Взгляды, хорошие мне. Если индексатор был не подписан (uint и т.д.), Вам, возможно, придется принять это во внимание. Назовите меня ленивым, но в том (неподписанном) случае, я мог бы просто использовать переменную счетчика:

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

(на самом деле, даже здесь необходимо было бы остерегаться случаев как прибытие. Длина = uint. MaxValue..., возможно, a! = где-нибудь..., конечно, который является очень маловероятным случаем!)

4
ответ дан Marc Gravell 5 November 2019 в 13:50
поделиться

Это - определенно лучший способ для любого массива, длина которого является целочисленным типом со знаком. Для массивов, длины которых являются неподписанным целочисленным типом (например, std::vector в C++), тогда необходимо изменить условие конца немного:

for(size_t i = myArray.size() - 1; i != (size_t)-1; i--)
    // blah

, Если Вы просто сказали i >= 0, это всегда верно для целого числа без знака, таким образом, цикл будет бесконечным циклом.

10
ответ дан Adam Rosenfield 5 November 2019 в 13:50
поделиться

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

, Что, будучи сказанным мои коллеги читают его и верят, это ценно 'где-нибудь'. Этот поток не является местом. Я ценил бы Вашу обратную связь на том, куда это должно пойти (я плохо знаком с сайтом).

<час>

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

*** Дополнительный метод, работающий по любому типу набора и берущий делегата действия, ожидающего единственное значение типа, все выполняемые по каждому объекту наоборот **

Requres 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 Тип массива наследовался интерфейсу IEnumerable (не универсальный IEnumerable только IEnumerable).

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

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

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

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

одноэлементный сервис А:

общедоступный класс ReverserService {частный 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);
      }
 }

общедоступный класс Testing123 [TestFixture] {

    /// <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;
    }
}
-4
ответ дан domain.dot.net team 5 November 2019 в 13:50
поделиться

В C#, с помощью Visual Studio 2005 или позже, тип 'forr' и хит [ВКЛАДКА] [ВКЛАДКА] . Это расширится до for цикл, который идет назад через набор.

столь легко понять превратно (по крайней мере, для меня), что я думал, вставляя этот отрывок, будет хорошая идея.

Однако я люблю Array.Reverse() / Enumerable.Reverse() и затем выполняю итерации вперед лучше - они более ясно заявляют намерение.

53
ответ дан MusiGenesis 5 November 2019 в 13:50
поделиться

В C# с помощью Linq:

foreach(var item in myArray.Reverse())
{
    // do something
}
17
ответ дан Keltex 5 November 2019 в 13:50
поделиться

В C++ у Вас basicially есть выбор между итерацией итераторов использования или индексов. В зависимости от того, есть ли у Вас простой массив, или std::vector, Вы используете различные методы.

Используя станд.:: вектор

Используя итераторы

C++ позволяет Вам делать это использование std::reverse_iterator:

for(std::vector<T>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it) {
    /* std::cout << *it; ... */
}

Используя индексы

, неподписанный целочисленный тип, возвращенный std::vector<T>::size, не всегда std::size_t. Это может быть больше или меньше. Это крайне важно для цикла для работы.

for(std::vector<int>::size_type i = someVector.size() - 1; 
    i != (std::vector<int>::size_type) -1; i--) {
    /* std::cout << someVector[i]; ... */
}

Это работает, так как неподписанные значения целочисленных типов определяются посредством модуля их количество битов. Таким образом, если Вы - установка -N, Вы заканчиваете в [1 112]

Используя Массивы

Используя итераторы

, Мы используем std::reverse_iterator, чтобы сделать итерацию.

for(std::reverse_iterator<element_type*> it(a + sizeof a / sizeof *a), itb(a); 
    it != itb; 
    ++it) {
    /* std::cout << *it; .... */
}

Используя индексы

Мы можем безопасно использовать std::size_t здесь, в противоположность вышеупомянутому, с тех пор sizeof всегда возвраты std::size_t по определению.

for(std::size_t i = (sizeof a / sizeof *a) - 1; i != (std::size_t) -1; i--) {
   /* std::cout << a[i]; ... */
}

ловушки Предотвращения с sizeof относились к указателям

На самом деле вышеупомянутый способ решить, что размер массива сосет. Если на самом деле указателя вместо массива (то, которое происходит довольно часто, и новички, перепутает его), это тихо перестанет работать. Лучший путь состоит в том, чтобы использовать следующее, которое перестанет работать во время компиляции, если дано подсказка:

template<typename T, std::size_t N> char (& array_size(T(&)[N]) )[N];

Это работает путем получения размера переданного массива сначала, и затем объявления для возврата ссылки на массив символа типа того же размера. char определяется для имения sizeof из: 1. Таким образом, возвращенный массив будет иметь sizeof из: N * 1, который является тем, что мы ищем, только с оценкой времени компиляции и обнуляем время выполнения наверху.

Вместо того, чтобы делать

(sizeof a / sizeof *a)

Изменение Ваш код так, чтобы это теперь сделало

(sizeof array_size(a))
113
ответ дан Ziezi 5 November 2019 в 13:50
поделиться

В C мне нравится делать это:


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

пример C#, добавленный MusiGenesis:

{int i = myArray.Length; while (i-- > 0)
{
    myArray[i] = 42;
}}
4
ответ дан MusiGenesis 5 November 2019 в 13:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: