从第n个元素开始迭代向量。

3
我想要从第n个元素开始迭代一个向量。不确定应该如何做。
我有一个名为A和B的向量。我的向量A有10个元素,分别是PC1-PC10,而我的向量B有20个元素,分别是User1-User20。 因此,当我的向量A和B都达到第十个元素时,也就是向量A的最后一个元素时,我想要重复迭代向量A,但是从第11个元素开始迭代向量B,以便进行一些操作。
下面是我想出来的简化代码,但从技术上讲,它们基本相同:
vector<string>::iterator b = vecB.begin();
for (int i = 1; i < 2; i++) {
    for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; a++) {
        if (a == vecA.end()) {
            b = vecB.begin() + 10; //here the iterator for verB should start from the 11th element
        }
    ++b
    }
}

我应该修改向量B的迭代器吗?还是有其他的替代方案?

编辑
看来我一直在问错问题。我已经标记了这个问题的答案,并将很快发布另一个问题。感谢您对我的快速回答!


检查一下 find() 能否帮到你,如果你知道要查找的元素。 - Rasmi Ranjan Nayak
你是否打算同时迭代两个向量的前10个元素?目前你没有增加b - eerorika
5个回答

4

嵌套循环内的if条件将永远不会成立,因为它与循环条件冲突:

for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; a++) {
// This check ----------------------------------^^^^^^^^^^^^^^^
// guarantees that this will never succeed:
//      vvvvvvvvvvvvvvv
    if (a == vecA.end()) {
        ...
    }
}

你应该像这样重写代码:
vector<string>::iterator b = vecB.begin();
// Check that vecB has sufficient number of elements before entering the loop.
for (int i = 1 ; i < 2 ; i++) {
    for (vector<string>::iterator a = vecA.begin(); a != vecA.end() ; ++a, ++b) {
        ...
    }
    // At this point we know for sure that a == vecA.end(),
    // because it is a post-condition of the for loop above.
    b = std::next(vecB.begin(), 11);
}

++b的调用可以移动到循环头中。

请注意使用std::next:尽管

b = vecB.begin() + 10;

虽然可以为向量编译,但并不保证所有类型的容器都能进行编译。请使用std::next代替:

b = std::next(vecB.begin(), 11);

注意:此代码假设vecB至少比vecA多有11个元素。如果在进入循环之前检查了这种情况,那么这可能没问题。但是如果这种假设被打破了,那么代码的行为将是未定义的。


@BaummitAugen 它适用于向量,但如果您将容器切换到其他内容,则 it + 10 可能无法编译。这就是为什么首先引入了 std::advancestd::next 的原因。 - Sergey Kalinichenko
我认为至少你应该限定“经常编译”和“不保证”,因为它看起来确实适用于std::vector - juanchopanza
您的回答假设vecB将始终至少有10个元素,我不会这样做(即使OP这样说,提出更安全的解决方案更好)。如果需要正确的行为,您可以始终检查vecA是否以第10个元素结束。 - zoska
那不应该是 next(..., 10) 吗? - Baum mit Augen
1
@BaummitAugen 看起来 OP 真的想要 11,因为他的代码中 ++b 在条件语句之后,中间没有任何东西。他还说“从第11个元素开始迭代向量B”。虽然我相信他会根据需要调整常数。 - Sergey Kalinichenko

1

其他人已经回答了如何重置或推进迭代器,因此我只会回答如何以更简单的方式解决您的问题。使用索引并行迭代两个向量要比使用两个迭代器简单得多:

// assumes vecB is bigger than vecA as described in the question
for (std::size_t i = 0; i < vecB.size(); i++) {
    auto user = vecB[i];
    auto pc = vecA[i % vecA.size()];
}

注意使用余数运算符迭代较小的向量。


向量大小的类型为“unsigned int”(尽管您的向量大小很少会超过有符号整数的最大值)。 - Gillespie
@RPGillespie 说得很有道理。我已经更正了类型。unsigned int也可能会溢出。std::vector<std::string>::size_type才是实际的类型,但是...那有点啰嗦。在大多数情况下,std::size_t应该是正确的。 - eerorika

0

你不需要改变B的迭代器,它会自动继续到第11个元素。但是你需要在for循环开始时重新开始对A进行迭代(或者你将使用无效的元素a.end()):

if (a == vecA.end()) {
    a = vecA.begin();
}

此外,您应该遍历两者,但仅在b上检查结束;如果您在a上检查,则for循环将在if条件为真之前结束:

for (auto a = vecA.begin(), b = vecB.begin(); b != vecB.end(); ++a, ++b)

你可以在这里看到整个代码。


1
然后在第二次迭代中跳过vecA的第一个元素。 - zoska
不,你不需要这样。你需要将它写成 for { if {}; doSomething;} 的形式。如果你将它写成 for { doSomething; if {}; } 的形式,那么你会在 if 前使用 a.end(),这是错误的。 - StenSoft
so refine it in your answer - zoska

0
除了使用@dasblinkenlight的答案中显示的std::next之外,您还可以使用std::advance
b = vecB.begin();
std::advance(b, 10);

我认为这并没有回答问题。OP只想要推进 std::vector::iterator,他现在的方式已经很好了。他问如何干净地迭代他的 vector - Baum mit Augen
std::advance 可以干净地推进 std::vector::iterator。它也可以推进其他迭代器并不会使其对于 std::vector::iterator 不干净,也不会比在您自己的函数中递增迭代器更不干净。 - R Sahu
但是,“如何提升任意迭代器?”并不是问题,也不能解决问题。问题在于他的循环有误,而不是it + 10对于std::unordered_map无法工作。 - Baum mit Augen

-1

我实际上更喜欢在C++11之前手动迭代向量,因为它看起来比迭代器更清晰和易读:

for (unsigned int i = 0; i < my_vector.size(); i++) {
    my_vector[i]; //Do Something
}

你可以通过修改for循环条件(即unsigned int i = n)来指定要迭代的范围。

编辑:在给我负评之前,请确实阅读完我的整个答案。在向量上使用迭代器过于冗长,使您的代码几乎无法阅读。如果有正当理由不应该使用此方法而应该使用迭代器,请留下评论。

大多数人并不需要一个超级通用的、可放入任何容器的解决方案。大多数人知道他们需要一个动态列表,vector正好符合要求,那么为什么不让你的代码易于阅读呢?


2
它如何回答任何问题? - zoska
@zoska OP说:“我正在尝试从第n个元素开始迭代一个向量。不确定该如何做。”我的答案清楚地展示了如何从第n个元素开始迭代一个向量。 - Gillespie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接