web-dev-qa-db-fra.com

itérateur pour vecteur 2D

Comment créer des itérateurs/s pour un vecteur 2D (un vecteur de vecteurs)?

22
miroslavec

Bien que votre question soit pas très claire, je vais supposer que vous voulez dire un vecteur 2D pour signifier un vecteur de vecteurs:

vector< vector<int> > vvi;

Ensuite, vous devez utiliser deux itérateurs pour le parcourir, le premier l'itérateur des "lignes", le second les itérateurs des "colonnes" de cette "ligne":

//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 ...
    }
}
42
Austin Hyde

Vous pouvez utiliser range for statement pour itérer tous les éléments d'un vecteur à deux dimensions.

vector< vector<int> > vec;

Et supposons que vous ayez déjà Push_back beaucoup d'éléments dans vec;

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

Une autre façon d'interpréter cette question est que vous voulez un itérateur 1D sur un vector<vector<>> Par exemple pour le nourrir dans for_each() ou un autre algorithme.

Vous pouvez faire ça comme ceci:

#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";
    }
}

Tirages:

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

Notez que cela ne fonctionnera pas avec std::sort() car cela nécessite un itérateur d'accès aléatoire. Vous pouvez en faire un itérateur à accès aléatoire mais vous devrez scanner le vecteur au début afin de pouvoir mapper un index plat vers idxOuter et idxInner en temps constant. Pas totalement banal mais pas difficile non plus.

9
Timmmm

Supposons que vous ayez un vecteur comme celui-ci: -

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

Maintenant, pour utiliser des itérateurs avec des vecteurs 2D: -

 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
  }



Un autre moyen plus court est également

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



Veuillez noter que la façon d'appeler des variables est différente dans les deux cas.

1
tanmay001

En supposant que vous voulez dire un vecteur de vecteurs et que vous avez std::vector à l'esprit, il n'y a pas de méthode intégrée pour le faire, car les itérateurs ne prennent en charge que les opérations d'incrémentation et de décrémentation pour avancer et reculer.

Un vecteur 2D est une matrice et vous auriez donc besoin de deux types d'itérateurs: un itérateur de ligne et un itérateur de colonne. Les itérateurs de ligne déplaceraient "vers le haut" et "vers le bas" la matrice, tandis que les itérateurs de colonne déplaceraient "vers la gauche" et "vers la droite".

Vous devez implémenter vous-même ces classes d'itérateurs, ce qui n'est pas nécessairement une chose triviale à faire. À moins, bien sûr, que vous vouliez simplement parcourir chaque emplacement de la matrice, auquel cas une double boucle for utilisant les variables d'index i et j fonctionnera très bien. En fonction de vos besoins (votre article manque un peu de contenu ici), vous pouvez utiliser boost::numeric::ublas::matrix, qui est une classe matricielle de la bibliothèque d'algèbre linéaire Boost. Cette classe de matrice possède des itérateurs de lignes et de colonnes intégrés, ce qui facilite généralement l'itération sur une matrice.

0
Charles Salvia

Vous pouvez utiliser le mot-clé automatique pour de tels cas:

#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;
}
0
Prakhar Gurawa

En supposant que vous entendiez un itérateur STL et un conteneur personnalisé qui implémente un tableau 2D générique d'objets, cela est impossible. Les itérateurs STL ne prennent en charge que les opérations d'incrémentation et de décrémentation (c'est-à-dire "suivant" et "précédent"), où le mouvement à travers un ensemble 2D nécessite quatre de ces primitives (par exemple, gauche/droite/haut/bas, etc.). Les métaphores ne correspondent pas.

Qu'essayez-vous de faire?

0
Andy Ross