2012-09-19 11 views
13

muszę dostęp do każdego elementu w wektorze, a także wiedzieć, co indeks element jest.Jak mogę iterować po wektorze, a także znać indeks elementu?

Dotychczas mogłem wymyślić dwa sposoby

for (iterator it= aVector.begin(), int index= 0; it!= aVector.end(); ++it, ++index) 

opuszczających podpis typu. również wygląda na to, że nie mogę używać auto-drukarki, która jest bardziej wydajna, czy jest lepszy sposób na zrobienie tego?

+1

Jeśli potrzeba * * indeks jakiegoś wewnętrznej, podstawowego powodu, a następnie użyć drugą wersję. –

+2

C++ nie ma "wyliczenia" – Fanael

+0

Tak, wolę drugie, jeśli potrzebujesz indeksu. –

Odpowiedz

12

Dla wektora lub innego pojemnika o dostępie swobodnym, to nie ma większego znaczenia. Prawdopodobnie wybrałbym drugi, ponieważ jest łatwiejszy do odczytania i prawdopodobnie marginalnie szybszy, ponieważ istnieje tylko jedna zmienna pętli do zaktualizowania. Inną alternatywą jest:

for (auto it = aVector.begin(); it != aVector.end(); ++it) { 
    int index = std::distance(aVector.begin(), it); 
} 

przypadku pojemników non-random-access, [] nie jest dostępny, a std::distance jest nieefektywne; w takim przypadku, jeśli potrzebujesz indeksu, pierwsza metoda byłaby lepsza (chociaż będziesz musiał to naprawić, aby nie próbował zadeklarować dwóch różnie wpisanych zmiennych w inicjalizatorze).

+0

To właśnie miałem na myśli: p – matiu

+0

Powinno to zostać naprawione, aby odzwierciedlić fakt, że 'std :: distance' zwraca' std :: iterator_traits :: difference_type', który będzie szerszym typem niż 'int '. (Fakt, że niewiele osób będzie miało pojemniki wystarczająco duże, aby przepełnić "int", nie jest usprawiedliwieniem.) Innym powodem jest użycie 'auto' - to dziwne, że zrobiłeś dla' it', ale nie dla 'index'. –

6

Odpowiedź jest w pytaniu - "wiedzieć, w jakim indeksie znajduje się element"..

Więc -

for (int index = 0; index < aVector.size(); ++index) 
{ 
    // access using [] 
} 

Performance-mądry są takie same (ale zawsze można sobie profil).

+1

indeks powinien być "size_t" zamiast "int" –

+3

@ Rémi pedantycznie, powinien to być wektor :: size_type :) –

0
for (iterator it = aVector.begin(), int index= 0; it!= aVector.end(); ++it, ++index) 

Nie skompiluje się. Ale tak naprawdę nie ma to znaczenia, ponieważ tak długo, jak mówimy o std::vector, dostęp do indeksu jest prostą arytmetyczną wskazówką i dereferencją - tak w rzeczywistości tak szybki, jak z iteratorem. Więc twoja wersja 2 jest w porządku.

Chciałbym jednak dalszej optymalizacji (jeśli jesteś naprawdę zaniepokojony prędkości):

for (int index = 0, size = aVector.size(); index < size; ++index) 
{ 
    // access using [] 
} 
+0

Dlaczego nie kompiluje się pierwszy? czy wprowadziłeś poprawny typ iteratora? – unj2

+0

@ kunj2aan: Ponieważ nie można zadeklarować zmiennych niepowiązanych typów ('iterator' i' int') w pojedynczej deklaracji. –

+0

@ kunj2aan Dlaczego po prostu nie spróbujesz (http://ideone.com/DF6TG). Zauważ, że [rozwiązanie jest proste] (http://ideone.com/yw5Lw). – Fiktik

0

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++ old school:

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; 
} 
+2

W pierwszym "i" jest elementem wektora, a nie indeksem lub iteratorem. Nie można uzyskać indeksu z pętli dla stylu zakresu. (W przypadku wektora możesz zhakować go za pomocą '& i- & vector [0]', ale przerwie to w sposób cichy i przerażający, jeśli zmieni się typ kontenera, więc nie rób tego). –

+0

@MikeSeymour masz rację, byłem zbyt spieszył. Dobry komentarz :) – matiu

+0

@MikeSeymour Myślę, że twój hack działałby tylko (?) Gdyby pętla for używała 'for (auto & i: aVector)', w przeciwnym razie, jak jest napisane, 'i' jest kopią element w wektorze. –

3

Oto rozwiązanie przy użyciu zip_iterator i counting_iterator od Boost.Iterator library. Prawdopodobnie jest to nadmierna pomyłka dla twojego przypadku użycia, ale ma ona zalety pracy z dowolnym zakresem (nie tylko wektorów) i dobrze pasuje do iteratora opartego na standardowym algorytmie, więc opublikuję go tutaj:

#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'; 
} 
1

można użyć Boost.Range za indexed adapter, który rozciąga się na iteratory Zakres jest z metodą index który zwraca aktualny indeks (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"; 

Niestety, ponieważ index to metoda na iteracyjnej część, oznacza to, że nie można korzystać z nowa gama opartych na pętli lub nawet BOOST_FOREACH, który tylko daje dostęp do elementu. Oto raczej boilerplate-y obejście o wątpliwej wartości:

// 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"; 
Powiązane problemy