STL:为向量写"where"运算符

Arm*_*man 8 c++ stl vector

我需要根据几个布尔谓词在向量中找到索引.

例如:

vector<float> v;
vector<int> idx;

idx=where( bool_func1(v), bool_func2(v), ... );
Run Code Online (Sandbox Code Playgroud)

声明**where**函数的方法是什么,以便在向量上使用几个用户定义的布尔函数?

谢谢阿曼.

一周后编辑

我用模板做了一些复杂的解决方案.但实际上valarray,我可以使用已预定义的任务.以下是可能会发现它有用的代码段:

  double dr=Rc/(double)Nbins, r;
  sigma.resize(Nbins);
  rr=sigma;
  valarray<double> vz(&data.vz[0], data.vz.size());
  double mvel=vz.sum()/(double)vz.size();
  for(size_t i=0l;i<Nbins;i++)
   {
   r=dr*i;
   valarray<bool> ids = (dist < r+dr) && (dist > r);//The magic valarray<bool>
   if(ids.max())
    {
    valarray<double> d=vz[ids];//we can use indirect operation.
    d-=mvel;
    d=pow(d,2.0);
    sigma[i]= sqrt(d.sum()/(double)d.size());
    rr[i]=r;
    cout<<i<<") "<<r<<" "<<sigma[i]<<endl;
    }
   }
Run Code Online (Sandbox Code Playgroud)

Edw*_*nge 10

Make your bool_xxx functions actually functors of a specific kind of type (tag dispatching would be enough). Then override || and && for them such that these operators return a bool_and, or bool_or. Then you can use your bool_ predicates like so:


std::find_if(vect.begin(), vect.end(), bool_x1() || bool_x2() && (bool_x3() || bool_x4() && bool_x5()));
Run Code Online (Sandbox Code Playgroud)

If you're tempted to write a "where" function then you apparently want to do this more than once with a different set of bool_xxx functions. Even if you know that you want a certain type of composition now, you may as well make it as universal as possible. This is how I'd do it.

Edit:

Based on this comment: @Jerry: For example I need to know: id=where(v < 10.0 && v>1.0); and somewhere later I would like to know: id=where(v < fun(v)); you may be better off with boost::lambda:


namespace l = boost::lambda;
std::find_if(vect.begin(), vect.end(), l::_1 < 10.0 && l::_1 > 1.0);
std::find_if(vect.begin(), vect.end(), l::_1 < l::bind(fun, l::_1));
Run Code Online (Sandbox Code Playgroud)

Or, if you hate lambda or aren't allowed to use it...or just want a very slightly nicer syntax (but inability to use functions directly) then just make your own placeholder type and override it to return bool_xxx functors on operators <, >, etc...

Edit2: Here's an untested where that returns a vector of iterators to all objects matching:


template < typename ForwardIter, typename Predicate >
std::vector<ForwardIter> where(ForwardIter beg, ForwardIter end, Predicate pred)
{
  ForwardIter fit = std::find_if(beg,end,pred);
  if (fit == end) return std::vector<ForwardIter>();

  ForwardIter nit = fit; ++nit;
  std::vector<ForwardIter> collection = where(nit,end,pred);
  collection.push_front(fit);
  return collection;
}
Run Code Online (Sandbox Code Playgroud)

It's recursive and could be slow on some implementations but there's one way to do it.

  • @Noah Roberts只是一个小注释:fit + 1实际上对前向迭代器不起作用,因为迭代器加法仅为随机访问迭代器定义.请改用std :: advance. (2认同)