How to create iterator/s for 2d vector (a vector of vecto开发者_如何学Gors)?
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 ...
}
}
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
}
}
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.
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.
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;
}
Since it's 2020, I'll post an updated and easy method. Works for c++11 and above as of writing. See the following example, where elements (here: tuples of <string, size_t>) of 2D vector (vector of vector) is iterated to compare with another value (string query) and the function then returns first element with match, or indicate "Not found".
tuple<string, size_t> find_serial_data( vector <vector <tuple <string, size_t>>> &serial,
string query)
{
for (auto& i : serial)
{
for (auto& j : i)
{
if ( get<0>(j).compare(query) == 0) return j;
}
}
cout << "\n Not found";
return make_tuple( "", 0);
}
Here is one example without the tuple thing:
string find_serial_data( vector <vector <string> > &serials,
string query)
{
for (auto& i : serials)
{
for (auto& j : i)
{
if ( j.compare(query) == 0) return j;
}
}
cout << "\n Not found";
return "";
}
Assuming you mean an STL iterator, and a custom container that implements a generic 2D array of objects, this is impossible. STL iterators support only increment and decrement (i.e. "next" an "previous") operations, where motion through a 2D set requires four such primitives (e.g. left/right/up/down, etc...). The metaphors don't match.
What are you trying to do?
Assuming you mean a vector of vectors, and you have std::vector
in mind, there's no built in way to do it, as iterators only support increment and decrement operations to move forward and backwards.
A 2D vector is a matrix, and so you'd need two iterator types: a row iterator and a column iterator. Row iterators would move "up" and "down" the matrix, whereas column iterators would move "left" and "right".
You have to implement these iterator classes yourself, which is not necessarily a trivial thing to do. Unless, of course, you simply want to iterate over each slot in the matrix, in which case a double for loop using index variables i
and j
will work just fine. Depending on your needs (your post is a bit lacking in content here), you may want to use boost::numeric::ublas::matrix
, which is a matrix class from the Boost linear algebra library. This matrix class has built-in row and column iterators, which make it generally easy to iterate over a matrix.
精彩评论