我们是否有一个增强的std :: remove_if STL函数,可以保留将被删除的元素

时间:2014-01-20 15:45:49

标签: c++ algorithm vector stl

现在假设我有一个数据列表,它保存在向量a中。我要做的是检查数据列表中的每个元素是否满足某些条件。如果是,则会将其从a中移除,然后保存在另一个向量b中。例如,在以下代码中,我可以轻松完成此任务:

class findOddClass
{
public:
    int Common; 
    findOddClass(int common):Common(common){};
    bool operator()(const int &i)
    {
        return (i%Common == 1);
    }

};

void testFunctionObject()
{
    std::vector<int> objArray;
   for(int i=0; i<10; i++)
       objArray.push_back(i);



   findOddClass finder(2);

   std::vector<int>::iterator it = objArray.begin();
   std::vector<int> oddArray;
   while(it != objArray.end())
   {
       if (finder(*it))
       {
           oddArray.push_back(*it);
           it = objArray.erase(it);
       }
       else
           it++; 

   }

    std::cout<<"Even array"<<std::endl;
   for(it=objArray.begin(); it != objArray.end(); it++)
       std::cout<<*it<<"    ";
   std::cout<<std::endl;

   std::cout<<"Odd array"<<std::endl;
   for(it= oddArray.begin(); it!=oddArray.end(); it++)
       std::cout<<*it<<"    ";
   std::cout<<std::endl;


}

但是,如果我想以更优雅的方式完成相同的任务:

 void testFunctionObject()
    {
        std::vector<int> objArray;
       for(int i=0; i<10; i++)
           objArray.push_back(i);


       std::vector<int>::iterator itEnd;
       itEnd = std::remove_if(objArray.begin(),objArray.end(),findOddClass(2));

       std::vector<int> oddArray;
       std::vector<int>::iterator it = itEnd;
       while(it != objArray.end())
       {
           oddArray.push_back(*it);
           it++;
       }

       objArray.erase(itEnd,objArray.end());


       std::cout<<"Even array"<<std::endl;
       for(it=objArray.begin(); it != objArray.end(); it++)
           std::cout<<*it<<"    ";
       std::cout<<std::endl;

       std::cout<<"Odd array"<<std::endl;
       for(it= oddArray.begin(); it!=oddArray.end(); it++)
           std::cout<<*it<<"    ";
       std::cout<<std::endl;

    }

它会失败。原因在于std::removal_if不会保留将被删除的元素的痕迹。我只是想知道STL中是否有功能可以完成这项工作,因此这是一种更优雅的工作方式。谢谢。

2 个答案:

答案 0 :(得分:3)

如果你想根据一些谓词将原始序列分成两个序列,我建议使用算法std :: partition_copy。当算法返回一对输出迭代器时,使用前一次调用std :: partition_copy的结果很容易应用方法擦除

template <class InputIterator, class OutputIterator1,
class OutputIterator2, class Predicate>
pair<OutputIterator1, OutputIterator2>
partition_copy(InputIterator first, InputIterator last,
OutputIterator1 out_true, OutputIterator2 out_false,
Predicate pred);

答案 1 :(得分:0)

std::partition对于可移动元素非常有效。勾勒出来,代码看起来像这样:

auto partition_point = std::partition(v1.begin(), v1.end(), predicate);
// Move the elements at the range to the other vector.
v2.assign(std::make_move_iterator(partition_point),
          std::make_move_iterator(v1.end()));
// Remove the remains from the original.
v1.erase(partition_point, v1.end());

优于partition_copy解决方案的优势在于,实际复制没有进行,这使得std::string或仅移动类型等类似句柄的事物更有效。