web-dev-qa-db-ja.com

ベクトルを反復処理し、要素のインデックスを知るにはどうすればよいですか?

ベクターの各要素にアクセスし、要素がどのインデックスにあるかを知る必要があります。

これまでのところ、2つの方法を考え出すことができます

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

型シグネチャーを残します。また、私は自動を使用できないように見えます

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

どちらがより効率的ですか、これを行うより良い方法はありますか?

28
unj2

ベクトルまたはその他のランダムアクセスコンテナーの場合、ほとんど違いはありません。読みやすいのでおそらく2番目を選択し、更新するループ変数が1つしかないため、おそらく2番目の方が高速です。別の選択肢は次のとおりです。

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

非ランダムアクセスコンテナーの場合、[]は利用できず、std::distanceは非効率的です。その場合、インデックスが必要な場合は、最初の方法の方が適切です(ただし、for-initialiserで2つの異なる型の変数を宣言しないように修正する必要があります)。

16
Mike Seymour

答えは質問にあります-"要素がどのインデックスにあるかを知っています。"

そう -

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

パフォーマンスに関しては同じです(ただし、いつでも自分でプロファイルできます)。

7
Luchian Grigore

Boost.IteratorライブラリZip_iteratorcounting_iteratorを使用したソリューションを次に示します。おそらくway過剰な使用例ですが、(ベクトルだけでなく)あらゆる範囲を操作できる利点があり、標準アルゴリズムの反復子ベースの設計なので、ここに投稿します。

#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

Boost.Rangeのindexedアダプターを使用できます。これは、現在のインデックス(duh)を返すindexメソッドで範囲のイテレーターを拡張します。

#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はイテレータのメソッドの一部であるため、これは新しい範囲ベースのforループや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";
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 ++オールドスクール:

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)

これはコンパイルされません。ただし、std::vectorについて説明している限り、インデックスによるアクセスは単純なポインタ演算と逆参照であるため、実際には問題ではありません。実際には、イテレータと同じくらい高速です。したがって、バージョン2は問題ありません。

しかし、私はさらに最適化します(本当に速度が気になる場合):

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