iterator for 2d vector

86,384

Solution 1

Although your question is not very clear, I'm going to assume you mean a 2D vector to mean a vector of vectors:

vector< vector<int> > vvi;

Then you need to use two iterators to traverse it, the first the iterator of the "rows", the second the iterators of the "columns" in that "row":

//assuming you have a "2D" vector vvi (vector of vector of int's)
vector< vector<int> >::iterator row;
vector<int>::iterator col;
for (row = vvi.begin(); row != vvi.end(); row++) {
    for (col = row->begin(); col != row->end(); col++) {
        // do stuff ...
    }
}

Solution 2

You can use range for statement to iterate all the elements in a two-dimensional vector.

vector< vector<int> > vec;

And let's presume you have already push_back a lot of elements into vec;

for(auto& row:vec){
   for(auto& col:row){
      //do something using the element col
   }
}

Solution 3

Another way to interpret this question is that you want a 1D iterator over a vector<vector<>> for example to feed it to for_each() or some other algorithm.

You can do that like this:

#include <iostream>

#include <iterator>
#include <vector>
#include <algorithm>

// An iterator over a vector of vectors.
template<typename T>
class vv_iterator : public std::iterator<std::bidirectional_iterator_tag, T>{
public:

  static vv_iterator<T> begin(std::vector<std::vector<T>>& vv) {
    return vv_iterator(&vv, 0, 0);
  }
  static vv_iterator<T> end(std::vector<std::vector<T>>& vv) {
    return vv_iterator(&vv, vv.size(), 0);
  }

  vv_iterator() = default;
  // ++prefix operator
  vv_iterator& operator++()
  {
    // If we haven't reached the end of this sub-vector.
    if (idxInner + 1 < (*vv)[idxOuter].size())
    {
      // Go to the next element.
      ++idxInner;
    }
    else
    {
      // Otherwise skip to the next sub-vector, and keep skipping over empty
      // ones until we reach a non-empty one or the end.
      do
      {
        ++idxOuter;
      } while (idxOuter < (*vv).size() && (*vv)[idxOuter].empty());

      // Go to the start of this vector.
      idxInner = 0;
    }
    return *this;
  }
  // --prefix operator
  vv_iterator& operator--()
  {
    // If we haven't reached the start of this sub-vector.
    if (idxInner > 0)
    {
      // Go to the previous element.
      --idxInner;
    }
    else
    {
      // Otherwise skip to the previous sub-vector, and keep skipping over empty
      // ones until we reach a non-empty one.
      do
      {
        --idxOuter;
      } while ((*vv)[idxOuter].empty());

      // Go to the end of this vector.
      idxInner = (*vv)[idxOuter].size() - 1;
    }
    return *this;
  }
  // postfix++ operator
  vv_iterator operator++(int)
  {
    T retval = *this;
    ++(*this);
    return retval;
  }
  // postfix-- operator
  vv_iterator operator--(int)
  {
    T retval = *this;
    --(*this);
    return retval;
  }
  bool operator==(const vv_iterator& other) const
  {
    return other.vv == vv && other.idxOuter == idxOuter && other.idxInner == idxInner;
  }
  bool operator!=(const vv_iterator &other) const
  {
    return !(*this == other);
  }
  const T& operator*() const
  {
    return *this;
  }
  T& operator*()
  {
    return (*vv)[idxOuter][idxInner];
  }
  const T& operator->() const
  {
    return *this;
  }
  T& operator->()
  {
    return *this;
  }

private:
  vv_iterator(std::vector<std::vector<T>>* _vv,
              std::size_t _idxOuter,
              std::size_t _idxInner)
    : vv(_vv), idxOuter(_idxOuter), idxInner(_idxInner) {}

  std::vector<std::vector<int>>* vv = nullptr;
  std::size_t idxOuter = 0;
  std::size_t idxInner = 0;
};



int main()
{
    std::vector<std::vector<int>> a = {{3, 5, 2, 6}, {-1, -4, -3, -5}, {100}, {-100}};
    std::reverse(vv_iterator<int>::begin(a), vv_iterator<int>::end(a));
    for (const auto& v : a)
    {
        std::cout << "{ ";
        for (auto i : v)
           std::cout << i << " ";
        std::cout << "}\n";
    }
}

Prints:

{ -100 100 -5 -3 }
{ -4 -1 6 2 }
{ 5 }
{ 3 }

Note this won't work with std::sort() because that requires a random access iterator. You could make it a random access iterator but you'd have to scan the vector at the start so you can map from flat index to idxOuter and idxInner in constant time. Not totally trivial but not hard either.

Solution 4

Suppose you have a vector like this:-

vector <vector<int>> vect{{1,2,3},{4,5,6},{7,8,9}};

Now to use iterators with 2D vectors :-

 for(auto i = vect.begin() ; i<vect.end() ; i++)
  {
     for(auto j = i->begin() ; j<i->end() ; j++)
        cout << *j <<" ";
     cout <<"\n";  
     //similarly you can do other things
  }



Also other shorter way is

 for(auto i : vect)
  {
     for(auto j : i)
        cout << j <<" ";
     cout << "\n";
//similarly you can do other things also.
  }



Please note the way of calling variables is different in both the cases.

Solution 5

You can use auto keyword for such cases:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;

int main() {
    // your code goes here
    vector<vector<int>>v;

    for(int i=0;i<5;i++)
    {
        vector<int> x={1,2,3,4,5};
        v.push_back(x);
    }
    cout<<"-------------------------------------------"<<endl;
    cout<<"Print without iterator"<<endl;
    cout<<"-------------------------------------------"<<endl;
    for(int i=0;i<5;i++)
    {
        vector<int> y=v[i];
        for(int j=0;j<y.size();j++)
        {
            cout<<y[j]<<" ";
        }
        cout<<endl;
    }
    cout<<"-------------------------------------------"<<endl;
    cout<<"Print with iterator"<<endl;
    cout<<"-------------------------------------------"<<endl;
    for(auto iterator=v.begin();iterator!=v.end();iterator++)
    {
        vector<int> y=*iterator;
        for(auto itr=y.begin();itr!=y.end();itr++)
        {
            cout<<*itr<<" ";
        }
        cout<<endl;
    }
    return 0;
}
Share:
86,384
miroslavec
Author by

miroslavec

Updated on November 08, 2020

Comments

  • miroslavec
    miroslavec over 3 years

    How to create iterator/s for 2d vector (a vector of vectors)?

    • UncleBens
      UncleBens over 14 years
      May-be describe the context of the question a bit better?
    • Mark Ransom
      Mark Ransom over 14 years
      More specifically: what is the declaration of your 2d vector? What order do you want to iterate? How do you want to use the iterator?
  • miroslavec
    miroslavec over 14 years
    Sorry that my question wasn't so clear but this is exactly what I wanted. Although I'm getting compiler error with this code: cannot convert from 'std::_Vector_iterator<_Ty,_Alloc>' to 'int' on for (row = vvi.begin(); row != vvi.end(); row++) {
  • miroslavec
    miroslavec over 14 years
    Exactly what I meant, 2D vector matrix with (now I know that two) iterators. I thought questions was clear :( ... anyway I'm quite new to vectors and I have to use them in this work. Now another problem is that error I posted in above comment (formating is shit). Can't assign value to first (row) iterator as because that type mismatch.
  • deft_code
    deft_code over 14 years
    always use pre increment operators. With vectors it's likely that it wont matter when using a vector but it's a bad habit to get into. Life would be much clearer if it had been ++C instead of C++.
  • Anoop Toffy
    Anoop Toffy almost 8 years
    If there are only 2 elements in the columns. How to access them once we iterate through row.
  • Austin Hyde
    Austin Hyde almost 8 years
    @Anoop Sorry, I don't understand your question? Do you mean you need to access *col[0] and *col[1]?
  • 463035818_is_not_a_number
    463035818_is_not_a_number about 6 years
    I was looking for exactly your interpretation of the question. Am I right, that this is only the non-const iterator and one would need to write a second class for the const_iterator? Is there any specific reason you store indices instead of the vector iterators? Btw it took me a while to understand the example, because the output uses the "normal" iterators, while the usage of the 1D iterator is a bit hidden in this innocent looking reverse line.
  • Timmmm
    Timmmm about 6 years
    Yes, in my actual code I have a const_iterator version. It's more or less a copy/paste with the non-const members removed (I couldn't find a way to avoid the copy/paste). Good point I guess there isn't a reason not to use vector iterators. That is probably better I just didn't think about it.