从C++中的非基元对象的向量中移除所有匹配元素

Remove all matching elements from vector of non-primitive objects in C++

本文关键字:元素 对象 C++ 向量      更新时间:2023-10-16

假设我有一个类:

class sampleVector
{
public:
int a;
int b;
string c;
}

现在我有一个带有sampleVector的多个对象的向量,但该向量有两个(多个(连续sampleVector对象,它们具有相同的值a(比如5(和b(比如10(。

现在,我想从向量中删除所有具有a=5和b=10的sampleVector对象。

问题是,对于多次连续发生,以下是一种方法:

for (;it!=itEnd;it++)
{
if (it->getA() == 5 && it->getB() == 10)
{
vec.erase(it);
it=vec.begin(); // Resetting this is must
}
}

但我想知道如何使用"删除",因为以下不起作用:

for (;it!=itEnd;it++)
{
if (it->getA() == 5 && it->getB() == 10)
{
vec2.erase(remove(vec2.begin(), vec2.end(), *it), vec2.end()); // doesn't even compile
}
}

当我们有一个原始数据类型的向量,并且有一个需要删除的特定值时,我们可以使用这种删除方式。但对于非原始数据类型的向量,我们如何通过传递迭代器而不是值来使用"remove"?

您不需要使用循环作为std::remove文档状态;

从范围[第一个,最后一个(中删除所有满足特定标准的元素

如果要删除只与类的一部分匹配的特定项,则应使用std::remove_if并提供谓词:

模板<class ForwardIt,class UnaryPredicate>ForwardIt remove_if(ForwardIt first,ForwardIt last,UnaryPredictate p(;

例如:

std::remove_if(std::begin(vec), std::end(vec),
[](sampleVector& v) { return (v.a == 5 && v.b==10); });

然后,您可以像以前一样将其传递到std::erase中。

您可以通过两种方式实现这一点:向类中添加一个比较运算符,或者将std::remove_if与执行比较的函数一起使用。

添加比较运算符

如果您可以访问类sampleVector,那么在大多数情况下,这种方法是首选的。通过这种方式,您可以将运算符与类一起分发,这样其他用户就不必为此编写函数。由于元素是公共的,您也可以将运算符作为非成员函数,但非成员函数将无法访问私有字段。

class sampleVector
{
public:
int a;
int b;
string c;
bool operator==(const sampleVector& other);
}
bool sampleVector::operator==(const sampleVector& other)
{
return a == other.a && b == other.b;
}
//somewhere else
sampleVector elementToRemove {5, 10, ""}; //or however you find the element you want to remove
std::erase(std::remove(vec2.begin(), vec2.end(), elementToRemove), vec2.end());

使用std::remove_if

如果您不能修改sampleVector的内容,或者有多种比较类的可能性(例如,在这里您只检查ab,但在其他情况下您也希望比较c(,则这种方法会更好。如果你想比较私人成员,这是行不通的(除非你为他们提供getter(。

std::erase(std::remove_if(vec2.begin(), vec2.end(), [](const sampleVector& v) {
return v.a == 5 && v.b == 10;}), vec2.end());

实际上std::remove算法不删除向量元素,而是在末尾移动这些元素。在您的情况下,您可以使用下一种方法:

auto it = std::remove_if(vec.begin(), vec.end(), [](auto&& item)
{ return (item.a == 5 && item.b == 10); });
vec.erase(it, vec.end());

备注:std::remove_if的第1个和第2个参数是迭代器,分别指示向量的开始和结束。第三个参数-是可调用的对象(在我们的例子中是lambda(,如果当前对象需要删除,则返回true,否则返回false。此算法的返回值-是第一个删除对象时的迭代器。

std::remove_if和vector.erase 的示例

#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
struct SampleVector
{
int a;
int b;
std::string c;
};
std::ostream& operator<<(std::ostream& to, const SampleVector & v)
{
return to << "{ a=" << v.a << ", b=" << v.b << ", c=" << v.c << " }";
}

int main(int argc, char const *argv[]) {
std::vector< SampleVector > data = { {5,10,"5-10"}, {3,12,"3-12"}, {5,10,"5-10"} };
std::cout << "Before [";
std::for_each(data.begin(), data.end(), [] (const SampleVector& v) {
std::cout << ' ' << v << ' ';
} );
std::cout << ']' << std::endl;
data.erase( std::remove_if(data.begin(), data.end(), [] (const SampleVector& v)
{ return 5 == v.a && 10 == v.b; } ), data.end() );

std::cout << "After [";
std::for_each(data.begin(), data.end(), [] (const SampleVector& v) {
std::cout << ' ' << v << ' ';
} );
std::cout << ']' << std::endl;
return 0;
}