web-dev-qa-db-ja.com

イテレーターを使用してベクターをナビゲートする方法は? (C ++)

目標は、[]演算子または「at」メソッドの代わりに、文字列のベクトルの「n番目」の要素にアクセスすることです。私が理解していることから、イテレーターはコンテナーをナビゲートするために使用できますが、以前にイテレーターを使用したことはなく、私が読んでいるものは混乱しています。

誰も私にこれを達成する方法に関する情報を提供できれば、私はそれを感謝します。ありがとうございました。

90
kevin

begin および end クラスのメソッド vector を使用する必要があります。これは、最初と最後の要素をそれぞれ参照するイテレータを返します。

using namespace std;  

vector<string> myvector;  // a vector of stings.


// Push some strings in the vector.
myvector.Push_back("a");
myvector.Push_back("b");
myvector.Push_back("c");
myvector.Push_back("d");


vector<string>::iterator it;  // declare an iterator to a vector of strings
int n = 3;  // nth element to be found.
int i = 0;  // counter.

// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ )    {
    // found nth element..print and break.
    if(i == n) {
        cout<< *it << endl;  // prints d.
        break;
    }
}

// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl;  // prints d.

// using the at method
cout << myvector.at(n) << endl;  // prints d.
94
codaddict

通常、反復子はコンテナの要素に直線的にアクセスするために使用されます。ただし、「ランダムアクセスイテレータ」を使用すると、operator[]と同じ方法で任意の要素にアクセスできます。

ベクトル内の任意の要素にアクセスするvecには、次を使用できます。

vec.begin()                  // 1st
vec.begin()+1                // 2nd
// ...
vec.begin()+(i-1)            // ith
// ...
vec.begin()+(vec.size()-1)   // last

以下は、典型的なアクセスパターン(以前のバージョンのC++)の例です。

int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
    sum += *it;
}

イテレーターを使用する利点は、他のコンテナーと同じパターンを適用できることです。

sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
    sum += *it;
}

このため、同じように機能するテンプレートコードを作成するのは非常に簡単ですコンテナタイプに関係なく。イテレータのもう1つの利点は、データがメモリに常駐していると想定しないことです。たとえば、入力ストリームからデータを読み取ることができるフォワードイテレータを作成したり、オンザフライでデータを単純に生成したりできます(範囲または乱数ジェネレータなど)。

std::for_eachとラムダを使用する別のオプション:

sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });

C++ 11以降では、autoを使用して、以前の(またはさらに複雑な)イテレーターの非常に長く複雑な型名の指定を回避できます。

sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
    sum += *it;
}

また、さらに簡単なfor-eachバリアントがあります。

sum = 0;
for (auto value : vec) {
    sum += value;
}

そして最後に、整数を追加するのか浮動小数点数を追加するのかに注意する必要があるstd::accumulateもあります。

52

C++-11では、次のことができます。

std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (auto i : v)
{
   // access by value, the type of i is int
   std::cout << i << ' ';
}
std::cout << '\n';

バリエーションについてはこちらをご覧ください: https://en.cppreference.com/w/cpp/language/range-for

36
lashgar

ベクターのイテレーターはランダムアクセスイテレーターです。つまり、プレーンポインターのように見えます。

コンテナのbegin()メソッドから返されたイテレータにnを追加してn番目の要素にアクセスするか、演算子[]を使用できます。

std::vector<int> vec(10);
std::Vector<int>::iterator it = vec.begin();

int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];

あるいは、あらゆる種類のイテレータで機能する advance 関数を使用できます。 (実際には、非ランダムアクセスイテレータで「ランダムアクセス」を実行するかどうかを検討する必要があります。これは、実行に費用がかかる可能性があるためです。)

std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();

std::advance(it, 5);
int sixth = *it;
15
UncleBens