J'ai besoin d'accéder à chaque élément d'un vecteur et de savoir dans quel index se trouve l'élément.
Jusqu'à présent, je pouvais trouver deux façons
for (iterator it= aVector.begin(), int index= 0; it!= aVector.end(); ++it, ++index)
en laissant la signature de type. aussi, on dirait que je ne peux pas utiliser l'auto
for (int index = 0; index < aVector.size(); ++index)
{
// access using []
}
Lequel est le plus efficace ou existe-t-il une meilleure façon de le faire?
Pour un vecteur ou un autre conteneur à accès aléatoire, cela fait peu de différence. Je choisirais probablement la seconde solution, car elle est plus facile à lire et est légèrement plus rapide car il n’ya qu’une variable de boucle à mettre à jour. Une autre alternative est:
for (auto it = aVector.begin(); it != aVector.end(); ++it) {
int index = std::distance(aVector.begin(), it);
}
[]
n'est pas disponible pour les conteneurs à accès non aléatoire et std::distance
est inefficace; dans ce cas, si vous avez besoin de l'index, la première méthode serait meilleure (bien que vous deviez la corriger afin d'éviter de déclarer deux variables de type différent dans le for-initialiser).
La réponse est dans la question - "savoir dans quel index se trouve l'élément." .
Alors -
for (int index = 0; index < aVector.size(); ++index)
{
// access using []
}
Les performances sont les mêmes (mais vous pouvez toujours vous profiler).
Voici une solution utilisant Zip_iterator
et counting_iterator
de la bibliothèque Boost.Iterator . Il s'agit probablement de way / overkill pour votre cas d'utilisation, mais il présente les avantages de travailler avec n'importe quelle plage (pas uniquement les vecteurs) et de l'adapter à la conception d'algorithmes standard basée sur l'itérateur. ici:
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/Zip_iterator.hpp>
#include <algorithm>
#include <iostream>
#include <list>
int main()
{
typedef std::list<int> container;
typedef boost::Tuple<
container::iterator,
boost::counting_iterator<container::size_type>
> Tuple_type;
typedef boost::Zip_iterator<Tuple_type> it_type;
container l{1, 2, 3, 4};
it_type begin(Tuple_type(l.begin(), 0));
it_type const end(Tuple_type(l.end(), l.size()));
// sample use with for loop
for (it_type it = begin; it != end ; ++it)
{
int value = it->get<0>();
int index = it->get<1>();
// do whatever you want with value and index
}
// sample use with standard algorithm
auto res = std::find_if(begin, end,
[](boost::Tuple<int, int> const & t)
{ return t.get<0>() > 2; }); // find first element greater than 2
std::cout << "Value: " << res->get<0>() << '\n' <<
"Index: " << res->get<1>() << '\n';
}
Vous pouvez utiliser l'adaptateur indexed
de Boost.Range, qui étend les itérateurs de la plage avec une méthode index
qui renvoie l'index actuel (duh).
#include <boost/range/adaptor/indexed.hpp>
// ...
auto&& r = vec | boost::adaptors::indexed(0);
for(auto it(begin(r)), ite(end(r)); it != ite; ++it)
std::cout << it.index() << ": " << *it << "\n";
Malheureusement, étant donné que index
fait partie d'une méthode de l'itérateur, cela signifie que vous ne pouvez pas utiliser la nouvelle boucle for basée sur la plage, ni même BOOST_FOREACH
, qui ne donne qu'un accès aux éléments. Voici une solution de contournement plutôt douteuse:
// note: likely contains typos or bugs
#include <boost/range/adaptors.hpp>
template<class IndexIt>
auto pair_index_value(IndexIt it)
-> std::pair<std::size_t, decltype(*it)>
{
return std::pair<std::size_t, decltype(*it)>(it.index(), *it);
}
// ...
using namespace boost::adaptors;
auto&& ir = vec | indexed; // because screw you Boost.Range
for(auto&& elem : boost::counting_range(ir.begin(), ir.end()) | transformed(pair_index_value))
std::cout << elem.first << ": " << elem.second << "\n";
c ++ 11:
for (auto i=aVector.begin(); i!=aVector.end(); ++i) {
cout << "I am at position: " << i-aVector.begin() << endl;
cout << "contents here is: " << *i << endl;
}
c ++ vieille école:
for (vector<int>::const_iterator i=aVector.begin(); i!=aVector.end(); ++i) {
cout << "I am at position: " << i-aVector.begin() << endl;
cout << "contents here is: " << *i << endl;
}
for (iterator it = aVector.begin(), int index= 0; it!= aVector.end(); ++it, ++index)
Cela ne compilera pas. Mais cela n'a pas vraiment d'importance, car tant que nous parlons de std::vector
, l'accès par index est un simple calcul arithmétique et déréférencé - donc en réalité aussi rapidement qu'avec l'itérateur. Donc, votre version 2 est OK.
Je voudrais cependant optimiser davantage (si vous êtes vraiment préoccupé par la vitesse):
for (int index = 0, size = aVector.size(); index < size; ++index)
{
// access using []
}