Search code examples
c++c++11vectorauto

Iterating over all but the first element in a vector


Suppose we have a vector of vectors and we initialize all elements to 0.

vector<vector<int>> P(MyObjects.size() + 1, vector<int>(MyBag.MaxCapacity + 1, 0));

My question is:

Is it possible to iterate over a vector starting from 1 column and 1 changing in someway following code?

for (auto& row : P) //Tried to add (row + 1) : P but I'm receiving an Error
  {
    for (auto& elem : row) //Tried to add(elem + 1) : row but I'm receiving an Error
    {
       std::cout << elem << "  ";
    }
  }

I was looking for the answer here on SO and on Web but there was nothing even similiar to it.

I'm only interested in solutions which use auto

EDIT: Here is the output of Errors

main.cpp:74:18: error: expected ‘;’ before ‘+’ token
   for (auto& row +1 : P)
                  ^
main.cpp:74:21: error: expected ‘;’ before ‘:’ token
   for (auto& row +1 : P)
                     ^
main.cpp:74:21: error: expected primary-expression before ‘:’ token
main.cpp:74:21: error: expected ‘)’ before ‘:’ token
main.cpp:74:21: error: expected primary-expression before ‘:’ token

And there is a Code which I was trying to use

for (auto& row + 1 : P)
  {
    for (auto& elem + 1 : row)
    {
     std::cout << elem << "  ";
    }
  }

Yes I know that we can use the following syntax

for(vector< vector<int> >::iterator row = v.begin() + 1; row != v.end(); ++row) {
    for(vector<int>::iterator col = row->begin() + 1; col != row->end(); ++col) {
        cout << *col;
    }
}

but I do not want to use it.


Solution

  • The expression on the right side of the colon here:

    for (auto& row : P) { ... }
                    ^^^
    

    has to be a container in the C++ sense. Something that you can call begin() and end() on that yields two iterators of the same (for now) type, where that iterator is incrementable, comparable, and dereferenceable.

    If what you want to do is skip the first element in the container, you'll need to create a new view of P that simply offsets the first iterator by one. What you're modifying is the container you're iterating over, not the values. So we want something like:

    for (auto& row : offset(P, 1)) { ... }
    

    offset takes a container and an offset that it'll apply to P's begin iterator:

    template <class C>
    iter_pair<iterator_t<C&>> offset(C& container, size_t skip) {
        return {std::next(container.begin(), skip), container.end()};
    }
    

    Where iter_pair is very straightforward:

    template <class It>
    struct iter_pair {
        It b, e;
    
        It begin() const { return b; }
        It end() const { return e; }
    };
    

    And iterator_t is buckets of fun. This is a simplified version:

    template <class C>
    using iterator_t = decltype(std::begin(std::declval<C>()));
    

    Demo