如何从具有特定值的stl向量中删除项?

时间:2008-09-02 16:14:13

标签: c++ stl

我正在查看stl向量的API文档,并注意到vector类上没有允许删除具有特定值的元素的方法。这似乎是一种常见的操作,看起来很奇怪,没有内置的方法可以做到这一点。

11 个答案:

答案 0 :(得分:151)

std::remove实际上并没有从容器中删除元素,但它确实返回了新的结束迭代器,可以将其传递给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());

答案 1 :(得分:57)

如果您要删除 项,以下内容会更有效。

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();
}

答案 2 :(得分:15)

将global方法std :: remove与begin和end迭代器一起使用,然后使用std :: vector.erase实际删除元素。

文档链接
std :: remove http://www.cppreference.com/cppalgorithm/remove.html
std :: vector.erase 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指出我的错误。

答案 3 :(得分:5)

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

使用已订购的容器,您最好使用std::vector::erase()。请注意,std::remove()中定义了<algorithm>,但实际上并没有进行删除。 (仔细阅读文档)。

答案 4 :(得分:5)

其他答案涵盖了如何很好地做到这一点,但我想我也会指出,这不是在矢量API中并不奇怪:它是低效的,线性搜索值的向量,其次通过一堆复制来删除它。

如果您正在密集地执行此操作,则可能因此考虑使用std :: set。

答案 5 :(得分:3)

更短的解决方案(不会强迫你重复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

答案 6 :(得分:2)

另请参阅std::remove_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".

答案 7 :(得分:1)

来自 c ++ 20

引入了一个非成员函数name,该函数将要删除的向量和值作为输入。

例如:

std::erase

答案 8 :(得分:1)

*

C ++社区已听到您的请求:)

*

C ++ 20 现在提供了一种简便的方法。 它变得简单:

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

您应该签出std::erasestd::erase_if

它不仅会删除值的所有元素(此处为“ 0”),而且会在 O(n) 时间复杂度下执行此操作。哪一种是最好的。

如果编译器不支持C ++ 20,则应使用erase-remove idiom

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

答案 9 :(得分:0)

如果你想在没有任何额外包含的情况下这样做:

device_id

答案 10 :(得分:0)

有两种方法可以用来擦除项目。 让我们取一个向量

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)有效方式(推荐):也称为 ERASE-REMOVE习惯用法

  • std :: remove将给定范围转换为一个范围,所有比较不等于给定元素的元素都移到了容器的开头。
  • 因此,实际上不要删除匹配的元素。 它只是将不匹配项转换为开始,并将迭代器赋予新的有效结束。 它只需要O(n)复杂度即可。

删除算法的输出是:

10 20 30 50 40 50 

remove的返回类型是迭代器到该范围的新末端。

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)