【问题标题】:STL algorithm copy if with functor [duplicate]如果使用函子,则 STL 算法复制 [重复]
【发布时间】:2014-07-13 13:20:24
【问题描述】:

以下情况可以使用哪种算法或算法组合?

struct Term
{
    int ix;
    double f;
};

std::vector<Term> terms = <intitalize terms>;
std::vector< int > termIxVector;

// NEED get all `ix` from the `terms` where term.f < 1.0, 
   // and insert 'ix' result to termIxVector.
//i.e. equavalent this loop:
for(std::size_t i = 0; i < terms.size(); ++i)
    if ( terms[i].f < 1.0 )
             termIxVector.push_back(terms[i].ix);

std::copy_if 仅复制 Term 结构。 std::transform - 不支持谓词。

【问题讨论】:

  • 一个普通的(基于范围的)for循环应该足够了。或者std::for_each,如果你真的想要&lt;algorithm&gt;。这不适合你吗?

标签: c++ algorithm c++11 stl


【解决方案1】:

std::for_each 与 lambda 一起使用

std::for_each(terms.begin(), terms.end(), 
              [&termIxVector](Term const& t) { 
                  if(t.f < 1.0) termIxVector.push_back(t.ix); 
              });

或基于for的范围

for(auto const& t : terms) {
  if(t.f < 1.0) termIxVector.push_back(t.ix);
}

【讨论】:

  • 抱歉,我使用的 Visual Studio 2010 不支持带捕获的 lambda(简单的 lambda 可以),并且基于范围的“for”也不支持。你不能在没有 lambda 和 range-base 'for' 的情况下显示吗?我比较有趣的算法组合。
  • VS2010 支持带捕获的 lambda,我们一直在使用它们。
  • @Khurshid 你从 VS2010 得到什么错误?我不再安装它,但我似乎记得捕获变量的 lambdas 在它上面工作得很好。如果您没有明确命名要捕获的变量怎么办? [&amp;](Term const&amp; t) { ... }
  • @Praetorian: VS2010 - 仅支持通过引用捕获 lambda,不支持按值显式捕获 - 通常 VS2010 100% 不支持 C++11 lambda。
  • @Khurshid 我不知道你在做什么。我通过引用而不是值来捕获向量。而且,我很确定 VS2010 两者都支持。如果我没记错的话,它唯一不支持的是将无捕获 lambda 隐式转换为函数指针。尝试代码,并发布您看到的任何错误。并且这里没有其他有趣的算法组合可以使用。您只需要一个 - for_each。如果您不想想使用 lambda,您可以手动创建一个仿函数,但它与 lambda 基本相同。
【解决方案2】:

这些基本算法的组合最方便使用Boost.Range

#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <iostream>
#include <iterator>
#include <vector>

struct Term
{
    int ix;
    double f;
};

int main()
{
    using namespace boost::adaptors;

    auto terms = std::vector<Term>{ {0, 0.1}, {1, 1.1}, {2, 0.8}, {3, 1.2}, {4, 0.9} };
    auto termIxVector = terms 
        | filtered([](auto const& x){ return x.f < 1.0; }) // select
        | transformed([](auto const& y){ return y.ix; })   // project
    ;    

    boost::copy(termIxVector, std::ostream_iterator<int>(std::cout, ","));    
}

Live Example 使用 Clang 3.5 SVN 打印 Term 元素的索引 0、2 和 4,其中 double 小于 1.0。

注意:这些范围是延迟计算的,termIxVector 实际上不是std::vector&lt;int&gt;。如果你想要那样,你需要做类似的事情

std::vector<int> termIxVector;
boost::push_back(termIxVector, /* RHS of the same range composition as above */);

【讨论】:

    【解决方案3】:

    如果您真的想使用std::copy_if,那么一个想法是在结构中重载operator int(),并使用标准的std::copy_if 和一元谓词(lambda 或仿函数),因为这将允许您转换@ 987654324@ 至int。代码如下:

    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <vector>
    
    struct Term{
        int ix;
        double f;
        operator int(){
            return ix;
        }
    };
    
    struct predicate{ // if you don't want a lambda
        bool operator()(const Term& t){
            return (t.f < 1.0 ? true : false);
        }
    };
    
    int main()
    {
        std::vector<Term> terms = {{1, 0.1}, {2, 0.2}, {3, 1.1}, {4, 0.9}};
        std::vector< int > termIxVector;
    
        std::copy_if(terms.begin(), terms.end(), 
                     back_inserter(termIxVector), predicate());
    
        for(auto& elem: termIxVector)
            std::cout << elem << std::endl;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-08
      • 2021-11-23
      • 2019-01-03
      相关资源
      最近更新 更多