【问题标题】:Do we have a enhanced std::remove_if STL function that can keep tract of the elements that will be removed我们是否有一个增强的 std::remove_if STL 函数可以保留将要删除的元素
【发布时间】:2014-01-20 15:45:48
【问题描述】:

假设现在我有一个保存在向量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 中是否有一个函数可以完成这项工作,因此是一种更优雅的工作方式。谢谢。

【问题讨论】:

    标签: c++ algorithm vector stl


    【解决方案1】:

    如果您想根据某些谓词将原始序列拆分为两个序列,我建议使用算法 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);
    

    【讨论】:

    • 糟糕,我错过了 partition_copy(与 copy 不同)对输入范围内的目的地没有任何限制。所以我认为这是正确的答案。
    【解决方案2】:

    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 等类似句柄的内容或仅移动类型更有效。

    【讨论】:

    • 如果您的类型有所不同,您可以将partition_copy(或任何其他复制算法)与移动迭代器一起使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多