2009-08-22 10 views
43

Często podczas iteracji przez ciąg (lub dowolny obiekt przeliczalny) nie jesteśmy zainteresowani jedynie bieżącą wartością, ale także pozycją (indeksem). Aby to osiągnąć za pomocą string::iterator musimy utrzymać oddzielny indeks:Jak mogę iterować przez ciąg znaków i znać indeks (aktualna pozycja)?

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

Przede styl wydaje się nie wydaje się lepsza od 'c-style'

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

w Ruby, możemy uzyskać zarówno treść i wskaźnik w elegancki sposób:

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

Więc, co to jest najlepsze praktyki w C++ do iteracji przez przeliczalnego obiektu, a także śledzenie aktualnego indeksu?

Odpowiedz

34

Nigdy nie słyszałem najlepszej praktyki dla tego konkretnego pytania. Jednak jedną z najlepszych praktyk jest użycie najprostszego rozwiązania, które rozwiązuje problem. W tym przypadku dostęp do stylu tablicy (lub styl c, jeśli chcesz go tak nazwać) jest najprostszym sposobem na iterację, gdy dostępna jest wartość indeksu. Tak więc z pewnością poleciłbym w ten sposób.

+0

przykład byłby miły: P –

42

Jak to:


    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

Na strunach, można użyć string.c_str() który zwróci Ci const char *, które mogą być traktowane jako tablicę, przykład:

const char* strdata = str.c_str(); 

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

To pytanie jest podobne do mojego, więc chciałbym zapytać tutaj, jak porównać wartość stardata [i] do ""? Czy istnieje sposób przekonwertowania go na char? – frogeyedpeas

6

dobra praktyka byłby oparty na czytelności, np .:

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

Lub:

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

Albo oryginalny:

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

Itd Cokolwiek jest najprostszym i najczystszych do ciebie.

Nie jest jasne, że istnieje jedna najlepsza praktyka, ponieważ potrzebna jest gdzieś zmienna licznika. Wydaje się, że pytanie, czy to, gdzie je zdefiniujesz, i jak jest zwiększane, działa dobrze dla ciebie.

+0

Moja poprzednia edycja jest poprawna, @Alex Reynolds. Sprawdź [Nie można zadeklarować dwóch zmiennych różnych typów w treści inicjującej pętli 'for' w' C++ '.] (Https://stackoverflow.com/questions/2687392/is-it-possible-to-declare -twojej-zmiennych-z-różnych-typów-w-pętli) i [to] (https://ideone.com/lngBfo). – Bateman

19

Można używać standardowych funkcji odległości STL jak wspomniano wcześniej

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

Ponadto, można uzyskać dostęp do znaków i kilka innych pojemników z interfejsem c-like:

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

btw, w moich wskaźnikach implementacji działają znacznie szybciej niż iteratory (5x i więcej) – Andrew

3

Chciałbym go użyć-str.begin() W tym szczególnym przypadku std :: odległość i operator - są takie same. Ale jeśli kontener zmieni się w coś bez dostępu losowego, std :: distance zwiększy pierwszy argument, aż osiągnie drugi, dając w ten sposób liniowy czas i operator - nie skompiluje się. Osobiście preferuję drugą zachowania - lepiej być powiadamiany, gdy algorytm z O (n) stał O (n^2) ...

1

Od std::distance jest tylko stała czasowa dla iteratory o dostępie swobodnym, to pewnie preferuj jawną iterację arytmetyczną. Ponadto, ponieważ piszemy tutaj kod C++, uważam, że lepszym rozwiązaniem jest idiomatyczne rozwiązanie C++ niż podejście w stylu C.

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

for (auto it = str.begin(), end = str.end(); it != end; ++it) 
{ 
    cout << it - begin << *it; 
} 
Powiązane problemy