如何从 stl 向量中移除具有某个值的项?

我查看了 stl 向量的 API 文档,注意到向量类中没有允许删除具有某个值的元素的方法。这似乎是一个常见的操作,而且似乎有点奇怪,没有内置的方式来做到这一点。

220646 次浏览

使用开始和结束迭代器的全局方法 std: : remove,然后使用 std: : vector.delete 实际删除元素。

文档链接
移除 http://www.cppreference.com/cppalgorithm/remove.html
抹去 http://www.cppreference.com/cppvector/erase.html

std::vector<int> v;
v.push_back(1);
v.push_back(2);


//Vector should contain the elements 1, 2


//Find new end iterator
std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);


//Erase the "removed" elements.
v.erase(newEnd, v.end());


//Vector should now only contain 2

感谢 Jim Buck 指出了我的错误。

另请参阅 Move _ if以便能够使用谓词..。

下面是上面链接中的例子:

vector<int> V;
V.push_back(1);
V.push_back(4);
V.push_back(2);
V.push_back(8);
V.push_back(5);
V.push_back(7);


copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 4 2 8 5 7"


vector<int>::iterator new_end =
remove_if(V.begin(), V.end(),
compose1(bind2nd(equal_to<int>(), 0),
bind2nd(modulus<int>(), 2)));
V.erase(new_end, V.end()); [1]


copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
// The output is "1 5 7".

std::remove实际上并没有从容器中删除元素: 它将要删除的元素移动到容器的末尾,并返回新的结束迭代器(end iterator) ,这个迭代器可以传递给 container_type::erase来实际删除现在位于容器末尾的额外元素:

std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());

如果您有一个未排序的向量,那么您可以简单地与最后一个向量元素 resize()交换。

有了定制的集装箱,你最好使用 std::vector::erase()。请注意,在 <algorithm>中定义了一个 std::remove(),但是它实际上并不执行擦除操作。(仔细阅读文档)。

其他的答案涵盖了如何做好这件事,但我想我也要指出,这并不是真正奇怪的矢量 API: 这是低效的,线性搜索通过向量的值,然后一堆复制删除它。

如果您正在集中地执行这个操作,那么出于这个原因,可以考虑使用 std: : set。

如果您想删除 一个项,下面的操作会更有效一些。

std::vector<int> v;




auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
v.erase(it);

或者,如果订单与你无关,你可以避免移动物品的开销:

std::vector<int> v;


auto it = std::find(v.begin(), v.end(), 5);


if (it != v.end()) {
using std::swap;


// swap the one to be removed with the last element
// and remove the item at the end of the container
// to prevent moving all items after '5' by one
swap(*it, v.back());
v.pop_back();
}

一个简短的解决方案(不会强迫你重复向量名4次)是使用 Boost:

#include <boost/range/algorithm_ext/erase.hpp>


// ...


boost::remove_erase(vec, int_to_remove);

参见 http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.html

如果你不想做任何额外的事情,包括:

vector<IComponent*> myComponents; //assume it has items in it already.
void RemoveComponent(IComponent* componentToRemove)
{
IComponent* juggler;


if (componentToRemove != NULL)
{
for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
{
if (componentToRemove == myComponents[currComponentIndex])
{
//Since we don't care about order, swap with the last element, then delete it.
juggler = myComponents[currComponentIndex];
myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
myComponents[myComponents.size() - 1] = juggler;


//Remove it from memory and let the vector know too.
myComponents.pop_back();
delete juggler;
}
}
}
}

有两种方法可以用来擦除一个项目,特别是。 让我们取一个矢量

std :: vector < int > v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(40);
v.push_back(50);

1)非高效方式: 虽然看起来非常高效,但这并不是因为擦除函数删除了元素,并将所有元素向左移动了1。 所以它的复杂度是 O (n ^ 2)

std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
if(*itr == value)
{
v.erase(itr);
}
else
++itr;
}

2)高效方法(推荐) : 它也被称为 [ em > ERASE-REMOVE 成语]

  • Remove 将给定的范围转换为一个范围,所有不等于给定元素的元素都移到容器的开始。
  • 所以,实际上不要删除匹配的元素。 它只是将非匹配项移动到开始位置,并给出一个迭代器以新的有效结束位置。 它只需要 O (n)复杂性。

移除算法的输出为:

10 20 30 50 40 50

因为 move 的返回类型是该范围的新末端的迭代器。

template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);

现在使用向量的擦除函数从向量的新端到旧端删除元素。它需要 O (1)时间。

v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );

所以这个方法适用于 O (n)

来自 C + + 20:

一个非成员函数引入了 std::erase,它将要移除的向量和值作为输入。

例如:

std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);

*

C + + 社区已经听到了你的请求:)

*

C + + 20 提供了一种简单的方法。 这很简单:

#include <vector>
...
vector<int> cnt{5, 0, 2, 8, 0, 7};
std::erase(cnt, 0);

你应该看看 删除擦除 _ if

它不仅会删除值的所有元素(这里是’0’) ,而且还会在 < em > O (n) 时间复杂度下执行。这是你能得到的最好结果了。

如果你的编译器不支持 C + + 20,你应该使用 删除-删除成语:

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

删除删除成语类似,对于 vector,可以使用 resizeremove并使用迭代器距离计算:

std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.resize(std::remove(vec.begin(), vec.end(), int_to_remove) - vec.begin());

测试 给你