从C ++中非原始对象的向量中删除所有匹配的元素

时间:2018-07-11 12:02:48

标签: c++ vector erase

让我说一堂课

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

现在我有一个带有多个sampleVector对象的向量,但是该向量具有2(多个连续个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
                }
        }

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

4 个答案:

答案 0 :(得分:6)

std::remove documentation状态中,您无需为此使用循环;

  

从[first,last)范围中删除所有满足特定条件的元素

当您要删除仅与班级部分匹配的特定项目时,应使用std::remove_if并提供谓词:

  

template <类ForwardIt,类UnaryPredicate>   ForwardIt remove_if(ForwardIt first,ForwardIt last,UnaryPredicate p);

例如:

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

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

答案 1 :(得分:2)

您可以通过两种方式实现这一点:向您的类添加一个比较运算符,或将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。如果您想比较私人成员(除非您为他们提供吸气剂),那么它将不起作用。

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

答案 2 :(得分:2)

实际上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的1st和2nd参数是分别指示向量的开始和结束的迭代器。 第3个参数-是可调用对象(在我们的示例中是lambda),返回true-如果当前对象需要删除,则返回false。 此算法的返回值-在第一个移除对象上是迭代器。

答案 3 :(得分:1)

带有std::remove_ifvector.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;
}