Подтвердить что ты не робот

Как выполнить итерацию по вектору, а также узнать индекс элемента?

Мне нужно получить доступ к каждому элементу в векторе, а также узнать, в каком индексе находится элемент.

До сих пор я мог придумать два пути.

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

оставляя подпись типа. также похоже, что я не могу использовать auto

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

Какой из них более эффективен или есть лучший способ сделать это?

4b9b3361

Ответ 1

Для векторного или другого контейнера с произвольным доступом это мало чем отличается. Я бы выбрал вторую, потому что ее легче читать и, вероятно, немного быстрее, поскольку для обновления требуется только одна переменная цикла. Другой вариант:

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

Для контейнеров без случайного доступа [] недоступен, а std::distance неэффективен; в этом случае, если вам нужен индекс, первый метод будет лучше (хотя вам нужно будет исправить его, чтобы он не пытался объявить две переменные в типичном для инициализатора).

Ответ 2

Ответ на вопрос - "знаете, в каком индексе находится элемент".

Итак -

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

По производительности они одинаковые (но вы всегда можете профилировать себя).

Ответ 3

Вот решение, использующее zip_iterator и counting_iterator из библиотеки Boost.Iterator. Вероятно, это может быть излишним для вашего случая использования, но у него есть преимущества работы с любым диапазоном (не только с векторами), и он идеально подходит для разработки стандартных алгоритмов на основе итератора, поэтому я размещаю его здесь:

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

Ответ 4

Вы можете использовать адаптер Boost.Range indexed, который расширяет итераторы диапазона с помощью метода index, который возвращает текущий индекс (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";

К сожалению, поскольку index является частью метода на итераторе, это означает, что вы не можете использовать новый цикл для цикла или даже BOOST_FOREACH, который дает только доступ к элементу. Здесь довольно укорачиваемое обходное решение сомнительного значения:

// 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";

Ответ 5

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

Это не будет компилироваться. Но это не имеет большого значения, потому что, пока мы говорим о std::vector, тогда доступ по индексу является простой арифметикой указателей и разыменованием - так на самом деле так же быстро, как и с итератором. Итак, ваша версия 2 в порядке.

Я бы, однако, оптимизировал (если вы действительно обеспокоены скоростью):

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

Ответ 6

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

С++ старая школа:

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