2009-08-22 15 views
43

A menudo, al iterar a través de una cadena (o cualquier objeto enumerable), no solo estamos interesados ​​en el valor actual, sino también en la posición (índice). Para lograr esto mediante el uso de string::iterator tenemos que mantener un índice separado:¿Cómo puedo iterar a través de una cadena y también conocer el índice (posición actual)?

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

Por encima de estilo parece no parece superior a la 'c-estilo'

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

En Rubí, podemos obtener tanto el contenido y el índice de una manera elegante:

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

Así que, ¿cuál es la mejor práctica en C++ para iterar a través de un objeto enumerable y también no perder de vista el índice actual?

Respuesta

34

nunca he oído de una mejor práctica para esta pregunta específica. Sin embargo, una mejor práctica en general es usar la solución más simple que resuelve el problema. En este caso, el acceso de estilo de matriz (o c-style si desea llamarlo así) es la forma más sencilla de iterar mientras tiene el valor de índice disponible. Así que ciertamente lo recomendaría de esa manera.

+0

un ejemplo sería bueno: P –

42

De esta manera:


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

Para las cadenas, puede utilizar string.c_str() que le devuelve un const char *, que puede ser entendido como una matriz, ejemplo:

const char* strdata = str.c_str(); 

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

Esta pregunta es similar a la mía, así que prefiero preguntar aquí, ¿cómo se compara el valor de stardata [i] con ""? ¿Hay alguna forma de convertirlo en char? – frogeyedpeas

6

Una buena práctica se basaría en la legibilidad, por ejemplo:

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

O:

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

O el original:

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

Etc. Lo que es más fácil y más limpio para usted.

No está claro si hay alguna práctica recomendada, ya que necesitará una variable contraria en alguna parte. La pregunta parece ser si el lugar donde lo define y cómo se incrementa le funciona bien.

+0

Mi edición anterior es correcta, @Alex Reynolds. Check [No es posible declarar dos variables de diferentes tipos en el cuerpo de inicialización de un bucle 'for' en' C++ '.] (Https://stackoverflow.com/questions/2687392/is-it-possible-to-declare -two-variables-of-different-types-in-a-for-loop) y [this] (https://ideone.com/lngBfo). – Bateman

19

Puede utilizar la función STL distancia estándar como se mencionó antes

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

También, puede acceder a cuerda y algunos otros recipientes con la interfaz similar a C:

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

por cierto, en mis índices de implementación funcionan mucho más rápido que los iteradores (5x y más) – Andrew

3

Yo usaría it-str.begin() En este caso particular std :: distance y operator- son iguales. Pero si el contenedor cambiará a algo sin acceso aleatorio, std :: distance incrementará el primer argumento hasta que llegue al segundo, dando así un tiempo lineal y el operador no compilará. personalmente prefiero la segunda comportamiento - es mejor que se le notifique cuando el algoritmo de O (n) se convirtió en O (n^2) ...

1

Desde std::distance es única constante de tiempo para los iteradores de acceso aleatorio, probablemente prefiera la aritmética explícita del iterador. Además, dado que estamos escribiendo código C++ aquí, creo que una solución idiomática de C++ es preferible a un enfoque de estilo C.

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

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