我查看了stl vector的API文档,发现vector类上没有允许删除具有特定值的元素的方法。这似乎是一个常见的操作,而且似乎奇怪的是,没有内置的方法来完成这项操作。
std::remove实际上不会从容器中删除元素,但它会返回新的end迭代器,该迭代器可以传递给container_type::erase来真正删除容器末尾的多余元素:
1 2 3 4
| 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 2 3 4 5 6
| std::vector<int> v;
auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
v.erase(it); |
或者,如果订单对您不重要,您可以避免移动项目的开销:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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();
} |
使用全局方法std::remove和begin和end迭代器,然后使用std::vector.erase实际删除元素。
文档链接标准::删除http://www.cppreference.com/cppalgorithm/remove.html标准::vector.erase http://www.cppreference.com/cppvector/erase.html
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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 |
感谢吉姆·巴克指出了我的错误。
其他的答案包括如何做好这件事,但我想我也会指出,这并不奇怪,这不在向量API中:它效率低下,通过向量线性搜索值,然后进行大量复制以删除它。
如果您正在集中执行此操作,那么出于这个原因考虑使用std::set是值得的。
如果您有一个未排序的向量,那么您可以简单地与最后一个向量元素交换,然后与resize()交换。
有了订好的集装箱,你最好还是带上?std::vector::erase()。注意,在中定义了一个std::remove(),但实际上并没有进行擦除。(仔细阅读文档)。
较短的解决方案(不强制您重复向量名4次)是使用boost:
1 2 3 4 5
| #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
另请参阅std::remove_if to be able to use a predicate…
下面是上面链接中的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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". |
来自C++ 20:
一个非成员函数引入了std::erase,它将要删除的向量和值作为输入。
前任:
1 2
| std::vector<int> v = {90,80,70,60,50};
std::erase(v,50); |
有两种方法可以用来特别删除项目。让我们取一个向量
1 2 3 4 5 6 7
| 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)
1 2 3 4 5 6 7 8 9 10 11
| std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
if(*itr == value)
{
v.erase(itr);
}
else
++itr;
} |
2)有效方法(推荐):也称为擦除-删除习语。
- 移除将给定范围转换为一个范围,所有与给定元素比较的元素都移到容器的开头。
- 所以,实际上不要删除匹配的元素。它只是将不匹配的转移到starting,并将迭代器赋给新的有效end。它只需要O(N)复杂性。
删除算法的输出是:
因为REMOVE的返回类型是该范围的新结尾的迭代器。
1 2
| template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val); |
现在使用vector的erase函数删除从新的元素到旧的元素。它需要O(1)次。
1
| v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () ); |
所以这个方法在O(n)中有效
如果你不想做任何额外的包括:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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;
}
}
}
} |