Мне нужно вернуться назад по массиву, поэтому у меня есть такой код:
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
}
Ответы:
Хотя это, по общему признанию, немного неясно, но я бы сказал, что наиболее приятный с точки зрения типографии способ сделать это
источник
В C ++ у вас есть выбор между итерацией с использованием итераторов или индексов. В зависимости от того, есть ли у вас простой массив или
std::vector
, вы используете разные методы.Использование std :: vector
Использование итераторов
C ++ позволяет делать это с помощью
std::reverse_iterator:
Использование индексов
Целочисленный тип без знака, возвращаемый функцией
std::vector<T>::size
, не всегдаstd::size_t
. Может быть больше или меньше. Это очень важно для работы цикла.Это работает, поскольку значения целочисленных типов без знака определяются по модулю их количества бит. Таким образом, если вы устанавливаете
-N
, вы попадаете в(2 ^ BIT_SIZE) -N
Использование массивов
Использование итераторов
Мы используем
std::reverse_iterator
для повторения.Использование индексов
Мы можем безопасно использовать
std::size_t
здесь, в отличие от вышеизложенного, так какsizeof
всегда возвращаетсяstd::size_t
по определению.Как избежать ошибок с применением sizeof к указателям
На самом деле описанный выше способ определения размера массива - отстой. Если a на самом деле является указателем, а не массивом (что случается довольно часто, и новички могут его запутать), он молча завершится ошибкой. Лучший способ - использовать следующее, которое не сработает во время компиляции, если задан указатель:
Он работает, получая сначала размер переданного массива, а затем объявляя возвращение ссылки на массив типа char того же размера.
char
определяется как имеющийsizeof
: 1. Таким образом, возвращаемый массив будет иметьsizeof
: N * 1, что мы и ищем, только с оценкой времени компиляции и нулевыми накладными расходами времени выполнения.Вместо того, чтобы делать
Измените свой код так, чтобы он
источник
end
иbegin
в обратном порядке?В C # , используя Visual Studio 2005 или новее, введите «forr» и нажмите [TAB] [TAB] . Это расширится до
for
цикла, идущего в обратном направлении по коллекции.Так легко ошибиться (по крайней мере, для меня), что я подумал, что вставить этот фрагмент будет хорошей идеей.
Тем не менее, мне нравится
Array.Reverse()
/,Enumerable.Reverse()
а затем лучше перебирать вперед - они более четко формулируют намерение.источник
Я всегда предпочитаю ясный код, а не « типографически приятный » код. Таким образом, я бы всегда использовал:
Вы можете рассматривать это как стандартный способ перемотки назад.
Всего два цента ...
источник
В C # с использованием Linq :
источник
Это определенно лучший способ для любого массива, длина которого является целым типом со знаком. Для массивов, длина которых представляет собой целочисленный тип без знака (например,
std::vector
в C ++), вам необходимо немного изменить конечное условие:Если вы только что сказали
i >= 0
, это всегда верно для целого числа без знака, поэтому цикл будет бесконечным.источник
Мне нравится. Если индексатор был без знака (uint и т. Д.), Возможно, вам придется это учитывать. Назовите меня ленивым, но в этом (беззнаковом) случае я мог бы просто использовать переменную-счетчик:
(на самом деле, даже здесь вам нужно быть осторожным с такими случаями, как arr.Length = uint.MaxValue ... может быть! = где-то ... конечно, это очень маловероятный случай!)
источник
В C мне нравится это делать:
Пример C #, добавленный MusiGenesis:
источник
Лучший способ сделать это в C ++ - это, вероятно, использовать адаптеры итератора (или, лучше, диапазона), которые будут лениво преобразовывать последовательность по мере ее прохождения.
В принципе,
Отображает диапазон "range" (здесь он пуст, но я уверен, что вы можете добавлять элементы самостоятельно) в обратном порядке. Конечно, простая итерация диапазона не очень полезна, но передача этого нового диапазона в алгоритмы и прочее - это довольно круто.
Этот механизм также можно использовать для гораздо более мощных целей:
Будет лениво вычислять диапазон «range», где функция «f» применяется ко всем элементам, элементы, для которых «p» не соответствует действительности, удаляются, и, наконец, результирующий диапазон меняется на противоположный.
Синтаксис конвейера - наиболее читаемый IMO, учитывая его инфикс. Ожидаемое рассмотрение обновления библиотеки Boost.Range реализует это, но это довольно просто сделать и самостоятельно. Еще круче с лямбда-DSEL генерировать функцию f и предикат p в строке.
источник
источник
Я предпочитаю цикл while. Для меня это более понятно, чем уменьшение
i
в условии цикла forисточник
Я бы использовал код в исходном вопросе, но если вы действительно хотите использовать foreach и иметь целочисленный индекс в C #:
источник
Я попытаюсь ответить на свой вопрос здесь, но мне это тоже не очень нравится:
источник
ПРИМЕЧАНИЕ. Этот пост оказался более подробным и, следовательно, не по теме, прошу прощения.
При этом мои сверстники читают его и считают, что это «где-то» ценно. Эта ветка не к месту. Буду признателен за ваш отзыв о том, куда это следует направить (я новичок на сайте).
В любом случае это версия C # в .NET 3.5, которая удивительна тем, что работает с любым типом коллекции, используя определенную семантику. Это мера по умолчанию (повторное использование!), А не минимизация производительности или цикла ЦП в наиболее распространенном сценарии разработки, хотя в реальном мире этого никогда не происходит (преждевременная оптимизация).
*** Метод расширения, работающий с любым типом коллекции и принимающий делегат действия, ожидающий единственного значения типа, все выполняется для каждого элемента в обратном порядке **
Требования 3.5:
Старые версии .NET или вы хотите лучше разобраться во внутреннем устройстве Linq? Читайте дальше .. Или нет ..
ПРЕДПОЛОЖЕНИЕ: В системе типов .NET тип Array наследуется от интерфейса IEnumerable (а не от универсального IEnumerable, только от IEnumerable).
Это все, что вам нужно повторить от начала до конца, однако вы хотите двигаться в обратном направлении. Поскольку IEnumerable работает с массивом типа 'object', допустим любой тип,
КРИТИЧЕСКОЕ ИЗМЕРЕНИЕ: Мы предполагаем, что если вы можете обработать любую последовательность в обратном порядке, что «лучше», то это можно сделать только с целыми числами.
Решение a для .NET CLR 2.0-3.0:
Описание: мы примем любой реализующий экземпляр IEnumerable с мандатом, согласно которому все содержащиеся в нем экземпляры относятся к одному типу. Итак, если мы получаем массив, весь массив содержит экземпляры типа X. Если какие-либо другие экземпляры имеют тип! = X, генерируется исключение:
Одноэлементный сервис:
открытый класс ReverserService {private ReverserService () {}
[TestFixture] открытый класс Testing123 {
источник