nikjohn nikjohn - 9 days ago 5
C++ Question

Iterating through a 2d vector with custom increment

I am trying to iterate through a large 2D vector (2 mil entries) and obtain some sample data. I figured out a good way of doing that would be to randomly shift my iterator to a random column, assign a random increment and repeat this process for every row.

Simplified Code:

#include <iostream>
#include <iterator>
#include <vector>
#include <ctime>

using namespace std;


int main()
{
srand((unsigned)time(0));
float _mean = 0;
vector<vector<size_t>> v{ { 1,2,3 },{ 4,5,6 },{ 7,8,9 } };
vector<vector<size_t> >::iterator row;
vector<size_t>::iterator column;
size_t i = 0;
size_t shift, inc;
for (row = v.begin(); row < v.end(); ++row)
{
shift = rand() % 10;
inc = rand() % 6;

for (column = row->begin()+shift; column < row->end(); column += inc) // row downshift
{
_mean += *column;
++i;
}
}
cout << _mean/i << endl;
system("pause");

}


The vector's size is not constant therefore, I can't really make it into a simple for loop without the use of iterators.

Also, I have identified, I think, the error that causes all this. The iterator increments out of range, but I still don't know how to (elegantly) fix it.

For a large vector the code works until it reaches the end of the row.
Do you have any suggestions that could help me out.

Thanks in advance.

Answer

There are two problems:

  • you can't assume that the end iterator can be compared for less than another iterator. This works only for random iterators (fortunately it's the case for vectors) and only if they are valid, i.e. within the bounds (which precisely isn't guaranteed in your code). So the for-condition should be column != row->end().
  • you risk to miss the end if inc>1 and if you miss the exact value of the end iterator.

The easiest alternative would be:

   for (int column = shift; column < row->size(); column += inc) // row downshift
    {
        _mean += (*row)[column];
        ++i;
    }

P.S.: * note that you could occasionally get an inc of 0 which would result in a infinite loop (see WhozCraig's comment). Better determine it with: inc = (rand() % 5) + 1;

Comments