web-dev-qa-db-ja.com

文字列を反復処理し、インデックス(現在の位置)を知るにはどうすればよいですか?

多くの場合、文字列(または列挙可能なオブジェクト)を反復処理するとき、現在の値だけでなく、位置(インデックス)にも関心があります。 string::iteratorを使用してこれを実現するには、個別のインデックスを維持する必要があります。

string str ("Test string");
string::iterator it;
int index = 0;
for ( it = str.begin() ; it < str.end(); it++ ,index++)
{
    cout << index << *it;
}

上記のスタイルは、「c-style」よりも優れているようには見えません。

string str ("Test string");
for ( int i = 0 ; i < str.length(); i++)
{
    cout << i << str[i] ;
}

Rubyでは、コンテンツとインデックスの両方をエレガントな方法で取得できます。

"hello".split("").each_with_index {|c, i| puts "#{i} , #{c}" }

それでは、列挙可能なオブジェクトを反復処理し、現在のインデックスを追跡するためのC++のベストプラクティスは何ですか?

54
pierrotlefou

この特定の質問のベストプラクティスについて聞いたことがありません。ただし、一般的なベストプラクティスの1つは、問題を解決する最も単純なソリューションを使用することです。この場合、配列スタイルのアクセス(またはそれを呼び出す場合はcスタイル)が、インデックス値を使用可能にしながら反復する最も簡単な方法です。だから私は確かにその方法をお勧めします。

46
TheUndeadFish

このような:


    std::string s("Test string");
    std::string::iterator it = s.begin();

    //Use the iterator...
    ++it;
    //...

    std::cout << "index is: " << std::distance(s.begin(), it) << std::endl;
48

前述のように、標準のSTL機能距離を使用できます

index = std::distance(s.begin(), it);

また、Cのようなインターフェイスを使用して文字列およびその他のコンテナにアクセスできます。

for (i=0;i<string1.length();i++) string1[i];
21
Andrew

良い習慣は読みやすさに基づいているでしょう、例えば:

string str ("Test string");
for (int index = 0, auto it = str.begin(); it < str.end(); ++it)
   cout << index++ << *it;

または:

string str ("Test string");
for (int index = 0, auto it = str.begin(); it < str.end(); ++it, ++index)
   cout << index << *it;

またはあなたのオリジナル:

string str ("Test string");
int index = 0;
for (auto it = str.begin() ; it < str.end(); ++it, ++index)
   cout << index << *it;

等あなたにとって最も簡単できれいなものは何でも。

どこかにカウンタ変数が必要になるため、ベストプラクティスが1つあるかどうかは明らかではありません。問題は、それをどこで定義し、どのように増分するかがあなたにとってうまくいくかどうかのようです。

10
Alex Reynolds

It-str.begin()を使用します。この特定のケースでは、std :: distanceとoperator-は同じです。しかし、コンテナがランダムアクセスなしで何かに変更されると、std :: distanceは2番目に達するまで最初の引数をインクリメントします。したがって、線形時間を与え、operator-はコンパイルされません。個人的には、2番目の動作を好みます-O(n)がO(n ^ 2)...になったときに通知される方が良いです...

3
maxim1000

std::distanceは、ランダムアクセス反復子の場合にのみ一定の時間であり、おそらく明示的な反復子演算を好むでしょう。また、ここではC++コードを記述しているため、CスタイルのアプローチよりもC++の慣用的なソリューションの方が望ましいと考えています。

string str{"Test string"};
auto begin = str.begin();

for (auto it = str.begin(), end = str.end(); it != end; ++it)
{
    cout << it - begin << *it;
}
1
user2015735

文字列の場合、string.c_str()を使用してconst char *を返すことができます。これは配列として扱うことができます。例:

const char* strdata = str.c_str();

for (int i = 0; i < str.length(); ++i)
    cout << i << strdata[i];
0
jscharf