C++如何按值而非位置删除向量元素?

345
vector<int> myVector;

假设向量中的值是这样的(按照此顺序):

5 9 2 8 0 7
如果我想删除包含值为“8”的元素,我认为我应该这样做:
myVector.erase(myVector.begin()+4);

因为这样会删除第四个元素。但是否有基于值 "8" 删除元素的方法?例如:

myVector.eraseElementWhoseValueIs(8);

还是我只需要迭代所有向量元素并测试它们的值?


6
@BenVoigt: 你的问题相当傲慢 - 显然那个人无法回答,你应该做的是创建一个回答,涵盖你提到的所有情况。 - slashmais
7
@slashmais: 哦,胡说八道,我的澄清问题非常简单,不需要专业程序员回答。我不可能涵盖所有三种情况下“你想要做什么”的所有可能取值。对于“没有匹配元素”的情况,可能的行为包括“什么也不做”、“抛出异常”、“返回错误”、“退出进程(可能通过 assert())”、“记录消息到 std::cerr”......甚至这些都不是穷尽所有可能。不,提问者需要说明错误处理策略,以及找不到匹配项是否算作错误。 - Ben Voigt
3
在QED的情况下,我认为。 - slashmais
4个回答

563

可以考虑使用std::remove()代替:

#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 8), vec.end());

这种组合也被称为擦除-移除惯用语


13
看一下remove()的描述:它将所有不等于传入值的值移动到范围[begin, end)的开头。使用你在问题中提供的例子,你将得到5, 9, 2, 0, 7, 7。然而,由于remove()返回新结尾的迭代器,如果需要的话,vec.erase()可以删除过时的元素(即此处的第二个7)。 - Georg Fritzsche
3
@Assimilater: 这并不必要。 - Georg Fritzsche
18
为什么你不能直接回答他的问题,而要发链接?是的,这是O(n)。 - user4222907
4
因为答案很容易在那里找到,这是更好的学习方法。 不同的人有不同的方法,这值得尊重。 - Georg Fritzsche
5
算法中的瑕疵在于remove不会在找到第一个匹配项时停止,继续比较列表的其余部分是低效的。因此,如果向量中可能存在多个相同值的副本,则这很好,但对于包含唯一值的向量来说并不是一个好答案。在这种情况下,使用std::find更为合适。 - srm
显示剩余6条评论

147

您可以使用std::find获取值的迭代器:

#include <algorithm>
std::vector<int>::iterator position = std::find(myVector.begin(), myVector.end(), 8);
if (position != myVector.end()) // == myVector.end() means the element was not found
    myVector.erase(position);

20
如果你只期望这个值出现一次,那么这是很好的。 - Tomáš Zato
17
或者只想删除其中一个,这似乎是这个问题的情况。 - Gauthier
3
为删除所有值,请初始化position = myVector.begin(),并将所有内容放在一个while(position != myVector.end())循环中。 - subtleseeker
xutility 中出现了 Error C2676 binary '==': 'action' does not define this operator or a conversion to a type acceptable to the predefined operator 错误。我尝试过的所有方法都无法解决这个问题。 - IOviSpot
因为这真的不是你应该做的方式(最受欢迎的答案是正确的方式),所以被投票否决。 - Carlo Wood
显示剩余5条评论

15

你不能直接这样做。你需要使用std::remove算法将要删除的元素移动到向量的末尾,然后使用erase函数。示例代码如下:myVector.erase(std::remove(myVector.begin(), myVector.end(), 8), myVec.end());。更多细节请参见从向量中删除元素


2

Eric Niebler正在进行一项范围提案,其中一些示例展示了如何删除某些元素。删除8会创建一个新向量。

#include <iostream>
#include <range/v3/all.hpp>

int main(int argc, char const *argv[])
{
    std::vector<int> vi{2,4,6,8,10};
    for (auto& i : vi) {
        std::cout << i << std::endl;
    }
    std::cout << "-----" << std::endl;
    std::vector<int> vim = vi | ranges::view::remove_if([](int i){return i == 8;});
    for (auto& i : vim) {
        std::cout << i << std::endl;
    }
    return 0;
}

输出结果

2
4
6
8
10
-----
2
4
6
10


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