Armen Tsirunyan
Armen Tsirunyan

Reputation: 133112

Iterating over a vector in reverse direction

I need to iterate over a vector from the end to the beginning. The "correct" way is

for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit)
{
    //do Something
}

When //do Something involves knowing the actual index, then some calculations need to be done with rit to obtain it, like index = v.size() - 1 - (rit - v.rbegin)

If the index is needed anyway, then I strongly believe it is better to iterate using that index

for(int i = v.size() - 1; i >= 0; --i)
{
    //do something with v[i] and i; 
}

This gives a warning that i is signed and v.size() is unsigned. Changing to

for(unsigned i = v.size() - 1; i >= 0; --i) is just functionally wrong, because this is essentially an endless loop :)

What is an aesthetically good way to do what I want to do which

Upvotes: 44

Views: 41904

Answers (11)

Kiruahxh
Kiruahxh

Reputation: 2075

You can cast the size to an int if your vector is not huge

for (int i = int(v.size()) - 1; i >= 0; --i) {
    //do something with v[i] and i; 
}

Upvotes: 0

Pavan Chandaka
Pavan Chandaka

Reputation: 12821

In C++20 one can use ranges (#include <ranges>)

//DATA
std::vector<int> vecOfInts = { 2,4,6,8 };

//REVERSE VECTOR 
for (int i : vecOfInts | std::views::reverse)
{
     std::cout << i << "  ";
} 

or if it is required to save in a different variable.

//SAVE IN ANOTHER VARIABLE
auto reverseVecOfInts = std::views::reverse(vecOfInts);

//ITERATION
for (int i : reverseVecOfInts)
{
    std::cout << i << "  ";
}

Upvotes: 5

Peter Arandorenko
Peter Arandorenko

Reputation: 196

for (it = v.end()-1; it != v.begin()-1; --it)
{
}

The "goes to" operator definitely messes with my head.

Upvotes: -3

Rob Kennedy
Rob Kennedy

Reputation: 163357

As you've noted, the problem with a condition of i >= 0 when it's unsigned is that the condition is always true. Instead of subtracting 1 when you initialize i and then again after each iteration, subtract 1 after checking the loop condition:

for (unsigned i = v.size(); i-- > 0; )

I like this style for several reasons:

  • Although i will wrap around to UINT_MAX at the end of the loop, it doesn't rely on that behavior — it would work the same if the types were signed. Relying on unsigned wraparound feels like a bit of a hack to me.
  • It calls size() exactly once.
  • It doesn't use >=. Whenever I see that operator in a for loop, I have to re-read it to make sure there isn't an off-by-one error.
  • If you change the spacing in the conditional, you can make it use the "goes to" operator.

Upvotes: 66

Nim
Nim

Reputation: 33655

to be aesthetically pleasing! ;)

for(unsigned i = v.size() - 1; v.size() > i; --i)

Upvotes: 7

Steve Townsend
Steve Townsend

Reputation: 54178

There's nothing to stop your reverse_iterator loop also using the index as described in multiple other answers. That way you can use the iterator or index as needed in the // do the work part, for minimal extra cost.

size_t index = v.size() - 1;
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); 
    rit != v.rend(); ++rit, --index)
{
  // do the work
}

Though I'm curious to know what you need the index for. Accessing v[index] is the same as accessing *rit.

Upvotes: 18

smerlin
smerlin

Reputation: 6566

loop condition i != std::numeric_limits<unsigned>::max() ... or use UINT_MAX if you think its to verbose. or another way:
for(unsigned j=0, end=v.size(), i=end-1; j<end; --i, ++j)
or
for(unsigned end=v.size(), i=end-1; (end-i)<end; --i)

Upvotes: 0

Sanja Melnichuk
Sanja Melnichuk

Reputation: 3505

Hi i think better way use iterator as you use in first sample and if you need get iterator index you can use std::distance to calculate it, if i understand your question

Upvotes: 0

Jean-Bernard Jansen
Jean-Bernard Jansen

Reputation: 7870

Try out a do while :

std::vector<Type> v;
// Some code 
if(v.size() > 0)
{
    unsigned int i = v.size() - 1;
    do
    {
        // Your stuff
    }
    while(i-- > 0);
}

Upvotes: 0

Yippie-Ki-Yay
Yippie-Ki-Yay

Reputation: 22854

I would prefer the reverse iterator variant, because it's still easy to interpret and allows to avoid index-related errors.

Sometimes you can simply use the BOOST_REVERSE_FOREACH, which would make your code look the following way:

reverse_foreach (int value, vector) {
   do_something_with_the_value;
}

Actually speaking, you can always use foreach statements for these kinds of loops, but then they become a bit unobvious:

size_t i = 0;

foreach (int value, vector) {
   do_something;
   ++i;
}

Upvotes: 2

Kylo
Kylo

Reputation: 2320

I think that:

for(unsigned i = v.size() - 1; i >= 0; --i)

is fine if you check

!v.empty()

earlier.

Upvotes: -3

Related Questions