从C++向量中按值删除一个元素。

21
如果我有

vector<T> list

如果列表中的每个元素都是唯一的,那么最简单的删除一个元素的方法是什么?我不知道它是否在列表中,也不知道它的索引,而且如果它不在列表中,我也不关心。


2
为什么vector容器的名称是list?这可能会让人感到困惑,尤其是对于阅读你的代码的人来说。 - Kiril Kirov
1
@KirilKirov,我不认为list是C++中的保留关键字?即使是这样,它只是一个例子。 - JimR
它是一种容器类型,就像vector一样。但两者非常不同 :) - Kiril Kirov
这是一个作业问题还是你正在尝试解决一个特定的问题?如果是后者,描述问题可能会给你提供替代解决方案;如果是前者,你应该将其标记为作业。 - AndersK
3
如果你的容器中所有元素必须是唯一的,并且你不需要使用其索引,那么你应该使用 std::set<T> 而不是 vector。 - Roman Kruglov
可能是重复的问题:如何从具有特定值的stl向量中删除项目? - bobobobo
4个回答

33
你可以使用Erase-remove idiom来操作std::vector
引用:
std::vector<int> v; 
// fill it up somehow
v.erase(std::remove(v.begin(), v.end(), 99), v.end()); 
// really remove all elements with value 99
如果你确定它是唯一的,那么就遍历这个向量并删除找到的元素。类似于以下代码:
for( std::vector<T>::iterator iter = v.begin(); iter != v.end(); ++iter )
{
    if( *iter == VALUE )
    {
        v.erase( iter );
        break;
    }
}

2
我想指出,你可以使用 find_if() 而不是直接迭代。 - Roman Kruglov
5
我的第二个答案... 我不会这样做。扩展到删除所有VALUE的出现将在两个可能的地方使人困惑:erase()后iter无效,++iter立即失败。必须写成iter=v.erase(iter);。现在,如果您以这种方式执行操作,将在擦除后提交额外的++iter,跳过元素。为了解决这个问题,应该在删除元素时始终__反向迭代__通过向量。使用数字索引可以解决这些问题。for (int i = v.size()-1; i >= 0; i--) if (v[i] == VALUE) v.erase(v.begin()+i); - bobobobo
我知道,但我说的是“扩展到删除”。 - bobobobo
@bobobobo - 是的,但这是另一种答案,不代表我的答案是错误的。 - Kiril Kirov

3
基于Kiril的回答,您可以在您的代码中使用以下函数:
template<typename T>
inline void remove(vector<T> & v, const T & item)
{
    v.erase(std::remove(v.begin(), v.end(), item), v.end());
}

并像这样使用它

remove(myVector, anItem);

3

如果每个元素都是唯一的,那么应该使用std::set<T>而不是std::vector<T>

这样做还有一个好处,即具有erase成员函数,可以实现你想要的功能。

看看使用正确的容器为任务提供了更多表达工具?

#include <set>
#include <iostream>

int main()
{
   std::set<int> notAList{1,2,3,4,5};

   for (auto el : notAList)
      std::cout << el << ' ';
   std::cout << '\n';

   notAList.erase(4);

   for (auto el : notAList)
      std::cout << el << ' ';
   std::cout << '\n';
}

// 1 2 3 4 5
// 1 2 3 5

在线演示


8
向量被用于某个特定目的,例如保留插入顺序。因此,“如果出现只有一次,则应使用 std::set<T> 而不是 std::vector<T>”这句话并不总是正确的。我们应该专注于原始问题的设定。 - xingzhi.sg

1

从C++20开始

//LIKE YOU MENTIONED EACH ELEMENT IS UNIQUE
std::vector<int> v = { 2,4,6,8,10 };

//C++20 UNIFORM ERASE FUNCTION (REMOVE_ERASE IDIOM IN ONE FUNCTION)
std::erase(v, 8); //REMOVES 8 FROM VECTOR

现在试试。
std::erase(v, 12);

不会发生任何事情,向量保持完整。


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