Итерация над вектором в обратном направлении
Мне нужно перебрать вектор с конца на начальный. "Правильный" способ -
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit)
{
//do Something
}
Когда doSomething включает в себя знание фактического индекса, тогда некоторые вычисления должны выполняться с помощью rit для его получения, например index = v.size() - 1 - (rit - v.rbegin)
Если индекс нужен в любом случае, то я твердо верю, что лучше итерации с использованием этого индекса
for(int i = v.size() - 1; i >= 0; --i)
{
//do something with v[i] and i;
}
Это дает предупреждение о том, что i
подписан, а v.size()
- без знака.
Переход на
for(unsigned i = v.size() - 1; i >= 0; --i)
является просто функционально неправильным, потому что это по существу бесконечный цикл :)
Что такое эстетически хороший способ сделать то, что я хочу сделать, что
- без предупреждения
- не включает трансляции
- не слишком многословный
Надеюсь, я не ищу чего-то, чего не существует:)
Ответы
Ответ 1
Как вы уже отметили, проблема с условием i >= 0
, когда он неподписан, заключается в том, что условие всегда истинно. Вместо вычитания 1 при инициализации i
, а затем после каждой итерации вычитайте 1 после проверки условия цикла:
for (unsigned i = v.size(); i-- > 0; )
Мне нравится этот стиль по нескольким причинам:
- Хотя
i
будет завернут до UINT_MAX
в конце цикла, он не будет полагаться на это поведение - он будет работать одинаково, если типы были подписаны. Опираясь на неподписанную оболочку, я чувствую себя немного взломанной.
- Он вызывает
size()
ровно один раз.
- Он не использует
>=
. Всякий раз, когда я вижу этот оператор в цикле for
, я должен его перечитать, чтобы удостовериться, что нет ошибки "один за другим".
- Если вы измените интервал в условном выражении, вы можете использовать его "перейти к" оператору.
Ответ 2
Нет ничего, чтобы остановить цикл reverse_iterator
, используя индекс, как описано в нескольких других ответах. Таким образом, вы можете использовать итератор или индекс по мере необходимости в части // do the work
для минимальной дополнительной стоимости.
size_t index = v.size() - 1;
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin();
rit != v.rend(); ++rit, --index)
{
// do the work
}
Хотя мне любопытно узнать, для чего нужен индекс. Доступ к v[index]
совпадает с доступом к *rit
.
Ответ 3
быть эстетически приятным!;)
for(unsigned i = v.size() - 1; v.size() > i; --i)
Ответ 4
Я бы предпочел вариант обратного итератора, потому что он все еще легко интерпретировать и позволяет избежать ошибок, связанных с индексами.
Иногда вы можете просто использовать BOOST_REVERSE_FOREACH
, чтобы ваш код выглядел следующим образом:
reverse_foreach (int value, vector) {
do_something_with_the_value;
}
На самом деле вы всегда можете использовать операторы foreach
для этих типов циклов, но затем они становятся немного неочевидными:
size_t i = 0;
foreach (int value, vector) {
do_something;
++i;
}
Ответ 5
Попробуйте сделать, пока:
std::vector<Type> v;
// Some code
if(v.size() > 0)
{
unsigned int i = v.size() - 1;
do
{
// Your stuff
}
while(i-- > 0);
}
Ответ 6
Привет, я думаю, что лучше использовать итератор, как вы используете в первом примере, и если вам нужно получить индекс итератора, вы можете использовать
std:: distance, чтобы вычислить его, если я понимаю ваш вопрос
Ответ 7
Условие цикла i != std::numeric_limits<unsigned>::max()
... или используйте UINT_MAX
, если вы думаете, что он является подробным.
или другим способом:
for(unsigned j=0, end=v.size(), i=end-1; j<end; --i, ++j)
или
for(unsigned end=v.size(), i=end-1; (end-i)<end; --i)
Ответ 8
for (it = v.end()-1; it != v.begin()-1; --it)
{
}
"переходит к" оператору", безусловно, беспорядок с моей головой.
Ответ 9
Я думаю, что:
for(unsigned i = v.size() - 1; i >= 0; --i)
отлично, если вы отметили
!v.empty()
ранее.