1

In Python, accessing an array's [-1]'th element gives the last element, and [-2] indexes the second to last element.

Is there a similar pretty syntax in C++ to access std::vector elements in reverse order?

a06e
  • 18,594
  • 33
  • 93
  • 169

5 Answers5

8

Revese iterators:

for (auto it = v.rbegin(); it != v.rend(); ++it)
{

}

If you want to access to the i-th element from the end:

*(v.rbegin() + i)

Or if you don't want to look like a know-it-all:

*(v.end() - i - 1)

Note that in Python you will actually use v[-i-1] to get to the same element, so this one uses the same number.

The trick is that vector iterators are RandomAccessIterator so you can add and substract indices to them.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • @becko: I just had noticed and was adding it ;-). – rodrigo Jul 29 '14 at 19:58
  • If you needed it for a container with forward iterators, you could use [`std::next`](http://en.cppreference.com/w/cpp/iterator/next), e.g. `*(std::next(l.rbegin(), i))`. – Fred Larson Jul 29 '14 at 20:04
  • @FredLarson: Right. But a container with forward iterators (not bidirectional) is not likely to implement `rbegin()` in the first place. This advice will probably be more useful for bidirectional iterators (not random-access). – rodrigo Jul 29 '14 at 20:10
  • 1
    Why not `v.rbegin()[i]`? – Marc Glisse Jul 29 '14 at 20:19
  • @MarcGlisse Sure. That would be identical, but I don't like too much the looks of `()[]`. – rodrigo Jul 29 '14 at 20:23
  • @MarcGlisse `v.rbegin()[i]` returns an iterator, or a reference? – a06e Jul 29 '14 at 20:36
  • 1
    `auto rv=v.rbegin();` and then you can use `rv[i]` as an equivalent for `v[size-1-i]`. – Marc Glisse Jul 29 '14 at 20:42
  • @MarcGlisse `v.rbegin()[i]` seems to be the slickest way. You should post an answer. – a06e Aug 04 '14 at 13:30
3

First, the other answers are great, and this one only complements them. Note that std::vector::reverse_iterator is a random access iterator. This means that you can use operator[] on it. In particular, the ith element starting from the last is v.rbegin()[i]. For convenience, you can define a variable auto rv = v.rbegin(); and then use rv[i] to access v[size-1-i].

Marc Glisse
  • 7,550
  • 2
  • 30
  • 53
0

You can use reverse iterators. Here you have a complete example on how to do it: .

But if you do not want to use a loop to traverse all the middle elements in the vector, you can also (along with reverse iterators) std::advance (it also traverses the vector as you would do it with a loop). Link to documentation.

You can also do it in the classical way: to access the last element you would do vector[vector.size()-1], to access the second element from the end vector[vector.size()-2]. I suppose you already knew it and were asking for a Python-look solution, but I do not know anything similar. Probably (but I am not sure) there is some way to overload the [] operator of the std::vector to allow what you are asking for. Here someone asked to do some changes in the way a vector operated: here.

Hope my answer was helpful.

Community
  • 1
  • 1
DanielFB
  • 33
  • 3
0

While @rodrigo's answer addresses the question well, I'd like to add one more point regarding looping through the std::vector.

In Python, looping through a list (or an iterable sequence in general) goes like:

mylist = [1, 2, 3, 4]

# from beginning to end
for elem in mylist:
    print(elem)

# from end to beginning
for elem in reversed(mylist):
    print(elem)

Since Python's for-loop is more akin to the "foreach" construct in other languages, the corresponding syntax in C++ actually uses the STL <algorithm>.

// header
#include <algorithm>

// example code
using namespace std;

vector<int> myvector {1, 2, 3, 4};

// forward
for_each(myvector.begin(), myvector.end(), [](int &elem){
    cout << elem << endl;
});

// reverse
for_each(myvector.rbegin(), myvector.rend(), [](int &elem){
    cout << elem << endl;
});

That last argument passed to std::for_each() is a lambda function which takes an int& as an argument.

Nasser Al-Shawwa
  • 3,573
  • 17
  • 27
0

Using Boost Range library:

#include <boost/range/adaptors.hpp>
#include <vector>
#include <iostream>

int main()
{
    std::vector<int> v {1,2,3,4,5};
    for (int i : v | boost::adaptors::reversed)
        std::cout << i << ' ';
}
jrok
  • 54,456
  • 9
  • 109
  • 141