如何在不越界的情况下遍历向量的最后一个元素?
How can I iterate through the last element of the vector without going out of bounds?
预期的输出是 1a1b1c 但我只得到 1a1b 如果我尝试在 for 循环中将 '-1' 放在 input.size() 旁边,但这只会忽略错误。我正在寻找的是我希望能够遍历字符串的最后一个成员而不会越界。
std::string input = "abc";
for (unsigned int i = 0; i < input.size(); i++){
int counter = 1;
while(input.at(i) == input.at(i+1) && i < input.size()-1){
counter++;
i++;
}
number.push_back(counter);
character.push_back(input.at(i));
}
几点供您参考:
1:for (unsigned int i = 0; i < input.size(); i++)
具体来说 i++
。这是一个后缀操作,意味着它 returns i 然后递增 i 的值。对于整数来说没什么大不了的,但是对于迭代器来说,这可能会变得非常昂贵,因为您每次都创建迭代器的副本。更愿意说出你的意思/你真正想要的,即增加 i,而不是获取 i 的副本并在之后增加 i。所以更喜欢 ++i
,它只会增加 i 而不会复制。
2:unsigned int i = 0
首先,它比使用具有符号 -> 无符号对话的 int 更好,每次与 input.size()
比较 returns 和 size_t
。其次 unsigned int
不能保证足够大以容纳字符串的大小并且需要从(可能)32 位 -> 64 位无符号提升以与 size_t
进行比较
3:认知复杂性,嵌套循环都改变了相同的不变量(在本例中为 i),这使得代码更难以推理,并且随着代码的演化最终会导致更多错误。在可能的情况下,只有一个地方可以改变循环不变量。
4:正如其他人所指出的,while 循环 while(input.at(i) == input.at(i+1) && i < input.size()-1)
可以超过字符串的大小,使用字符串的 .at
成员函数将抛出越界访问。这可以通过将嵌套循环重构为单个循环来简单地通过第 3 点解决。
5:避免对 .at
的多次调用,我们完全控制用于索引字符串的索引,因此只要我们可以保证我会,您就可以安全地使用 operator[]
始终是一个有效的索引,在这种情况下我认为你可以。
6:i < input.size()
使用 <
当它不是您想要的支票并且它比您真正想要的支票 i != input.size()
贵得多时。在 compiler explorer
中查看这个简单的比较
谢天谢地,来自 shadowranger 的修复完全解决了您的问题,即:while(i < s.size()-1 && s.at(i) == s.at(i+1))
但是我想提供一个没有嵌套循环的替代方案来向您展示如何避免我的第 3、4、5 点和 6 :
void do_the_thing(std::string const& s) {
std::cout << "Considering: \"" + s + "\"\n";
if(s.empty()) {
return;
}
size_t const length = s.length(); // avoiding repeated calls to length which never changes in this case
if(length == 1) {
std::cout << "1" << s[0] << "\n";
return;
}
std::vector<unsigned> number;
std::vector<char> character;
// do the stuff your example did
char last = s[0];
unsigned same_count = 1;
for(size_t ii = 1; ii != length; ++ii) {
char const cur = s[ii];
if(cur == last) {
++same_count;
} else {
number.push_back(same_count);
character.push_back(last);
last = cur;
same_count = 1;
}
}
if(*s.rbegin() == last) {
number.push_back(same_count);
character.push_back(last);
}
// print the things or use them in some way
assert(number.size() == character.size());
size_t const out_len = character.size();
for(size_t ii = 0; ii != out_len; ++ii) {
std::cout << number[ii] << character[ii];
}
std::cout << "\n";
}
预期的输出是 1a1b1c 但我只得到 1a1b 如果我尝试在 for 循环中将 '-1' 放在 input.size() 旁边,但这只会忽略错误。我正在寻找的是我希望能够遍历字符串的最后一个成员而不会越界。
std::string input = "abc";
for (unsigned int i = 0; i < input.size(); i++){
int counter = 1;
while(input.at(i) == input.at(i+1) && i < input.size()-1){
counter++;
i++;
}
number.push_back(counter);
character.push_back(input.at(i));
}
几点供您参考:
1:for (unsigned int i = 0; i < input.size(); i++)
具体来说 i++
。这是一个后缀操作,意味着它 returns i 然后递增 i 的值。对于整数来说没什么大不了的,但是对于迭代器来说,这可能会变得非常昂贵,因为您每次都创建迭代器的副本。更愿意说出你的意思/你真正想要的,即增加 i,而不是获取 i 的副本并在之后增加 i。所以更喜欢 ++i
,它只会增加 i 而不会复制。
2:unsigned int i = 0
首先,它比使用具有符号 -> 无符号对话的 int 更好,每次与 input.size()
比较 returns 和 size_t
。其次 unsigned int
不能保证足够大以容纳字符串的大小并且需要从(可能)32 位 -> 64 位无符号提升以与 size_t
3:认知复杂性,嵌套循环都改变了相同的不变量(在本例中为 i),这使得代码更难以推理,并且随着代码的演化最终会导致更多错误。在可能的情况下,只有一个地方可以改变循环不变量。
4:正如其他人所指出的,while 循环 while(input.at(i) == input.at(i+1) && i < input.size()-1)
可以超过字符串的大小,使用字符串的 .at
成员函数将抛出越界访问。这可以通过将嵌套循环重构为单个循环来简单地通过第 3 点解决。
5:避免对 .at
的多次调用,我们完全控制用于索引字符串的索引,因此只要我们可以保证我会,您就可以安全地使用 operator[]
始终是一个有效的索引,在这种情况下我认为你可以。
6:i < input.size()
使用 <
当它不是您想要的支票并且它比您真正想要的支票 i != input.size()
贵得多时。在 compiler explorer
谢天谢地,来自 shadowranger 的修复完全解决了您的问题,即:while(i < s.size()-1 && s.at(i) == s.at(i+1))
但是我想提供一个没有嵌套循环的替代方案来向您展示如何避免我的第 3、4、5 点和 6 :
void do_the_thing(std::string const& s) {
std::cout << "Considering: \"" + s + "\"\n";
if(s.empty()) {
return;
}
size_t const length = s.length(); // avoiding repeated calls to length which never changes in this case
if(length == 1) {
std::cout << "1" << s[0] << "\n";
return;
}
std::vector<unsigned> number;
std::vector<char> character;
// do the stuff your example did
char last = s[0];
unsigned same_count = 1;
for(size_t ii = 1; ii != length; ++ii) {
char const cur = s[ii];
if(cur == last) {
++same_count;
} else {
number.push_back(same_count);
character.push_back(last);
last = cur;
same_count = 1;
}
}
if(*s.rbegin() == last) {
number.push_back(same_count);
character.push_back(last);
}
// print the things or use them in some way
assert(number.size() == character.size());
size_t const out_len = character.size();
for(size_t ii = 0; ii != out_len; ++ii) {
std::cout << number[ii] << character[ii];
}
std::cout << "\n";
}