Как я могу перебирать строку, а также знать индекс (текущая позиция)?
Часто при итерации по строке (или любому перечислимому объекту) нас интересует не только текущее значение, но и позиция (индекс). Чтобы добиться этого, используя 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}" }
Итак, что лучше всего использовать в С++ для итерации через перечислимый объект, а также отслеживать текущий индекс?
Ответы
Ответ 1
Я никогда не слышал о лучшей практике для этого конкретного вопроса. Однако одной из лучших практик в целом является использование простейшего решения, которое решает проблему. В этом случае доступ в виде массива (или c-style, если вы хотите его назвать) - это самый простой способ итерации при наличии доступного значения индекса. Поэтому я, конечно, рекомендую этот путь.
Ответ 2
Вот так:
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;
Ответ 3
Вы можете использовать стандартное расстояние функции STL, как указано выше
index = std::distance(s.begin(), it);
Кроме того, вы можете получить доступ к строкам и некоторым другим контейнерам с c-подобным интерфейсом:
for (i=0;i<string1.length();i++) string1[i];
Ответ 4
Хорошая практика будет основана на удобочитаемости, например:
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;
Etc. Что бы ни было проще и чище для вас.
Не ясно, есть ли какая-то лучшая практика, поскольку вам где-то понадобится переменная-счетчик. Кажется, что вопрос о том, где вы его определяете и как он увеличивается, хорошо работает для вас.
Ответ 5
Я бы использовал его-str.begin()
В этом конкретном случае std:: distance и operator - одинаковы. Но если контейнер изменится на что-то без произвольного доступа, std:: distance будет увеличивать первый аргумент до тех пор, пока он не достигнет второго, давая таким образом линейное время и оператор - не будет компилироваться.
Лично я предпочитаю второе поведение - лучше быть уведомленным, когда алгоритм из O (n) стал O (n ^ 2)...
Ответ 6
Для строк вы можете использовать string.c_str()
, который вернет вам const char *, который можно рассматривать как массив, например:
const char* strdata = str.c_str();
for (int i = 0; i < str.length(); ++i)
cout << i << strdata[i];
Ответ 7
Так как std::distance
- это только постоянное время для итераторов с произвольным доступом, я бы предпочел явно арифметику итератора.
Кроме того, поскольку мы пишем здесь код С++, я верю, что более идиоматическое решение на С++ предпочтительнее, чем подход C-стиля.
string str{"Test string"};
auto begin = str.begin();
for (auto it = str.begin(), end = str.end(); it != end; ++it)
{
cout << it - begin << *it;
}