web-dev-qa-db-fra.com

Comment puis-je parcourir un vecteur et connaître également l'index de l'élément?

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?

20
unj2

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).

15
Mike Seymour

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).

7
Luchian Grigore

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';
}
3
Luc Touraille

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";
3
Xeo

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;
}
1
matiu
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 []
}
0
Fiktik