Iterating C++ vector from the end to the beginning
One way is:
for (vector<my_class>::reverse_iterator i = my_vector.rbegin();
i != my_vector.rend(); ++i ) {
}
rbegin()
/rend()
were especially designed for that purpose. (And yes, incrementing a reverse_interator
moves it backward.)
Now, in theory, your method (using begin()
/end()
& --i
) would work, std::vector
's iterator being bidirectional, but remember, end()
isn't the last element — it's one beyond the last element, so you'd have to decrement first, and you are done when you reach begin()
— but you still have to do your processing.
vector<my_class>::iterator i = my_vector.end();
while (i != my_vector.begin())
{
--i;
/*do stuff */
}
UPDATE: I was apparently too aggressive in re-writing the for()
loop into a while()
loop. (The important part is that the --i
is at the beginning.)
Iterating over a vector in reverse direction
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 toUINT_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 afor
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.
How should I loop over the elements of a C++ container in reverse order?
Well, first of all, about your two snippets: Part of the problem is that they're a bit bug prone for actual newbies - the integer underflow, off-by-one in the comparison, forgetting what i
signifies and using it as a plain index etc. So I would definitely recommend something else. Also, those snippets may invoke vec.size()
many times, which, if the compiler isn't optimizing well enough, would mean a bunch of redundant work.
Option 1: Use iterators
You can reverse-iterate over a container using a pair of iterators (std::rbegin
and std::rend
, and their constant variants) which represent the reversal of the container's order of elements. Here's what that looks like:
for(auto it = std::crbegin(vec); it != std::crend(vec); it++) {
std::cout << *it << '\n';
}
I made this option the first because it's (mostly) compatible with C++98. We didn't have std::rbegin()
and std::crbegin()
then, but we did have an rbegin()
method for std::vector
. std::crbegin()
was introduced in C++11
Option 2: Using C++11 (and later) ranged-for loops
You can massage your container - without making a copy of it (although possibly with some payment of time), so that you can use the result in ranger for loop. The answers to this SO question describe several ways to do so, enabling the following code:
auto reverse_view = /* magic involving vec; and not making a copy */
for(auto x : reverse_view) {
std::cout << *it << '\n';
}
They involve either using an "infrastructural" library (namely Boost), or writing a few lines of code which return an iterator pair in an std::pair
- which is enough for C++ to use in a ranged-for loop.
Option 3: Using ranged-for and C++20's ranges support
Finally, in C++20, this all becomes easier - with ranges support and std::ranges::reverse_view
:
auto reverse_view = std::ranges::reverse_view{vec};
for (const auto& x : reverse_view) {
std::cout << x << '\n';
}
Performance note
Reverse-iterating can in some cases be expensive - because moving backwards, or finding the end of the container, is not always trivial or free. Think of a unidirectional list (where each element comes with a pointer to the next one) - whenever you want to go backwards, you need to traverse the whole list up to your current element to know where the previous element is located. Not all containers are like vectors...
Traversing a vector in reverse direction with size_t values
If you actually want to use size_t
for indexing, the loop could be formulated as follows.
for(size_t r = m.size(); r > 0; r--)
{
x[r-1] = f[r-1];
for(size_t c = r; c < m.size(); c++)
{
x[r-1] -= m[r-1][c] * x[c];
}
}
Basically you would iterate from m.size()
to 1
and compensate by shifting inside the loop; but this solution might be a bit hard to follow. In this question, a proposed solution is to use a reverse_iterator
, which can be seen as a suitable abstraction of the index. The entire topic is coverd in more depth in this question.
c++ Iterate through vector with variable direction
I would so something like this, using a standard library algorithm and reverse iterators where appropriate. For example,
void foo(int i) { /* do stuff */ }
if (smth)
std::for_each(vec.begin(), vec.end(), foo);
else
std::for_each(vec.rbegin(), vec.rend(), foo);
Traverse a list in reverse order in Python
Use the built-in reversed()
function:
>>> a = ["foo", "bar", "baz"]
>>> for i in reversed(a):
... print(i)
...
baz
bar
foo
To also access the original index, use enumerate()
on your list before passing it to reversed()
:
>>> for i, e in reversed(list(enumerate(a))):
... print(i, e)
...
2 baz
1 bar
0 foo
Since enumerate()
returns a generator and generators can't be reversed, you need to convert it to a list
first.
Related Topics
Why Gcc Does Not Use Load(Without Fence) and Store+Sfence for Sequential Consistency
Is There a Reason Declval Returns Add_Rvalue_Reference Instead of Add_Lvalue_Reference
Is Using a Vector of Boolean Values Slower Than a Dynamic Bitset
Visual Studio Project Out of Date
Is It Ever Not Safe to Throw an Exception in a Constructor
What Exactly Is Va_End For? Is It Always Necessary to Call It
Lambdas Require Capturing 'This' to Call Static Member Function
How to Create a Type List (For Variadic Templates) That Contains N-Times the Same Type
How to Determine the Correct Size of a Qtablewidget
Avoid Warning 'Unreferenced Formal Parameter'
C++ Remove_If on a Vector of Objects
What Is the Use of Volatile Keyword
PDF Specifications for Coders: Adobe or Iso
How to Test If a Constexpr Function Is Evaluated at Compile Time
Why Does Initializing an Extern Variable Inside a Function Give an Error