从向量中删除项目

Posted

技术标签:

【中文标题】从向量中删除项目【英文标题】:Removing items from a vector 【发布时间】:2014-05-24 18:44:53 【问题描述】:

我正在寻找从向量中删除多个项目的最有效方法?

基本上,我将在向量中搜索一个标志并删除具有该标志的对象。

但是,我听说从向量中擦除对象会弄乱您的迭代器,那么循环遍历向量(可能包含数千个对象)并删除带有特定标志的对象的最有效方法是什么?

我希望不必多次循环遍历向量。

【问题讨论】:

std::remove_if. 如何不弄乱迭代器:iterator = vector.erase(iterator); 向量中项目的顺序是否重要?如果没有,每当您遇到要删除的向量中的项目时,将该项目设置为等于向量中的最后一项,然后在向量上调用 pop_back()。通过这样做,您可以在 O(N) 时间内从向量中删除任意数量的项目。 (请注意,它确实会改变项目的顺序,所以如果这是一个问题,请改用 std::remove_if()) 【参考方案1】:

如果有多个元素匹配标志你应该使用std::remove_if():

vec.erase(std::remove_if(vec.begin(), v.end(), [](T const& e) return e.flag(); ),
          v.end());

使用这种方法,每个向量元素最多移动一次。删除单个元素可能会移动每个元素O(n) 次。

【讨论】:

我不确定“up to O(n)”是否是一个合理的表达方式。 O(n) 已经意味着“最多”... 干杯,太完美了:) 它怎么能移动每个元素一次,还要O(n)次? @soandos:例如,假设您从序列中删除第一个 n/2 元素,一次一个元素。您将移动每个后半部分元素n/2 次。 那么“使用这种方法最多移动每个向量元素一次”是什么意思?您的意思是删除吗?【参考方案2】:

std::remove_if 算法有时可以与其他实用程序优雅地结合使用。例如,如果您的课程如下所示:

struct Foo

    bool flag;               // either this...
    bool get_flag() const;   // ... or this
    // ...
;

那么你可以使用std::mem_fn来生成一个访问器函子,分别返回成员的值或者调用成员函数:

std::mem_fn(&Foo::flag)
std::mem_fn(&Foo::get_flag)

最后,您可以使用参数相关查找来依赖命名空间std,只要其中一个参数类型来自该命名空间即可找到。例如:

#include <algorithm>   // for remove_if
#include <functional>  // for mem_fn
#include <iterator>    // for begin, end
#include <vector>      // for vector

std::vector<Foo> v = /* something */ ;

v.erase(remove_if(begin(v), end(v), std::mem_fn(&Foo::flag)), end(v));

【讨论】:

另请参阅this code review,了解mem_fn 谓词的一些限制。

以上是关于从向量中删除项目的主要内容,如果未能解决你的问题,请参考以下文章

访问冲突 C++(删除向量中的项目)

从向量中删除对象会破坏 C++ 中另一个对象中的对象

从向量中删除取消引用的元素

此代码是从向量中添加和删除项目的线程安全方式吗?

将项目从一个向量复制到另一个向量

如何从 PySpark 中的向量结构中获取项目