views:

247

answers:

3

The goal is to access the "nth" element of a vector of strings instead of the [] operator or the "at" method. From what I understand, iterators can be used to navigate through containers, but I've never used iterators before, and what I'm reading is confusing.

If anyone could give me some information on how to achieve this, I would appreciate it. Thank you.

+4  A: 

Typically, iterators are used to access elements of a container in linear fashion; however, with "random access iterators", it is possible to access any element in the same fashion as operator[].

To access arbitrary elements in a vector vec, you can use the following:

1st: vec.begin()
2nd: vec.begin()+1
3rd: vec.begin()+2
4th: vec.begin()+3
...
ith: vec.begin()+(i-1)
...
last: vec.begin()+(vec.size()-1)

The following is an example of a typical access pattern using an iterator.

int sum = 0;
for (std::vector<int>::const_iterator it = vec.begin(); it!=vec.end(); ++it) {
    sum += *it;
}

The advantage of using iterator is that you can apply the same pattern with other containers:

int sum = 0;
for (std::list<int>::const_iterator it = lst.begin(); it!=lst.end(); ++it) {
    sum += *it;
}

For this reason, it is really easy to create template code that will work the same regardless of whether the container is a vector, a list, or some other container. Another advantage of iterators is that it doesn't assume the data is resident in memory; for example, one could create a forward iterator that can read data from an input stream, or that simply generates data on the fly (e.g. a range or random number generator).

Michael Aaron Safyan
+1  A: 

You need to make use of the begin and end method of the vector class, which return the iterator referring to the first and the last element respectively.

    vector<string> myvector; // a vector of stings.

    // push some stirngs in the vector.
    myvector.push_back("a");
    myvector.push_back("b");
    myvector.push_back("c");
    myvector.push_back("d");


    vector<string>::iterator it; // declare an iterator to a vector of strings
    int n = 3; // nth element to be found.
    int i = 0; // counter.

    // now start at from the beginning
    // and keep iterating over the element till you find
    // nth element...or reach the end of vector.
    for(it=myvector.begin() ; it < myvector.end(); it++,i++ ) {

            // found nth element..print and break.
            if(i == n) {
                    cout<< *it; // prints d.
                    break;
            }
    }

    // other easier ways of doing the same.
    // using operator[]
    cout<<myvector[n]<<endl; // prints d.

    // using the at method
    cout<<myvector.at(n)<<endl; // prints d.
codaddict
This misses the fact that `std::vector` has random access iterators.
sbi
Regardless of whether you know the iterator type is random-access or not, the "best" way to move an iterator forward n spaces is not to write your own loop, but to call `std::advance(it, n)`. It's defined to do exactly what you want, and it will automatically use `it + n` if the iterator is tagged as random-access, or do the loop if it has to.
Steve Jessop
+1  A: 

Vector's iterators are random access iterators which means they look and feel like plain pointers.

You can access the nth element by adding n to the iterator returned from the container's begin() method, or you can use operator [].

std::vector<int> vec(10);
std::Vector<int>::iterator it = vec.begin();

int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];

Alternatively you can use the advance function which works with all kinds of iterators. (You'd have to consider whether you really want to perform "random access" with non-random-access iterators, since that might be an expensive thing to do.)

std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();

std::advance(it, 5);
int sixth = *it;
UncleBens
You can use `advance` for random-access iterators too, or iterators of unknown category, since it is guaranteed to operate in constant time in that case. This is why user-defined iterators should be correctly tagged.
Steve Jessop
Indeed, but `advance` is really annoying to use (because of the out parameter usage) if you know you are dealing with random access iterators. Would only recommend in generic code, and if not used a lot (if the algorithm doesn't support non-random-access iterators well, so be it - for example, `std::sort` *could* sort a `std::list` but it doesn't because it would be ridiculously inefficient).
UncleBens
Sure, the classic example would be if your algorithm only actually *needs* an InputIterator, but for whatever reason it sometimes skips ahead, so you want it to be more efficient if the iterator does have random access. It's not worth restricting your algorithm to random access only by using `operator+`. But the question was explicitly about vector, so there's nothing wrong with the first part of your answer. I just thought the second part might imply "you can't use advance with random access iterators, even if you want to" to someone who has never seen `advance` before.
Steve Jessop
OK, reworded that bit and gave the example with a vector.
UncleBens