简体   繁体   English

C ++ boost或STL`y + = f(x)`类型算法

[英]C++ boost or STL `y += f(x)` type algorithm

I know I can do this y[i] += f(x[i]) using transform with two input iterators. 我知道我可以使用两个输入迭代器的变换来做y[i] += f(x[i]) however it seems somewhat counterintuitive and more complicated than for loop. 然而,它似乎有点违反直觉,比循环更复杂。

Is there a more natural way to do so using existing algorithm in boost or Stl. 有没有更自然的方法来使用boost或Stl中的现有算法。 I could not find clean equivalent. 我找不到干净的等价物。

here is transform (y = y + a*x): 这里是变换(y = y + a * x):

using boost::lambda;
transform(y.begin(), y.end(), x.begin(), y.begin(), (_1 + scale*_2);
//  I thought something may exist:
transform2(x.begin(), x.end(), y.begin(), (_2 + scale*_1);
// it does not, so no biggie. I will write wrapper

Thanks 谢谢

There are several ways to do this. 有几种方法可以做到这一点。

As you noted you can use transform with a number of predicates, some more or less automatically generated: 如您所述,您可以将transform与多个谓词一起使用,或多或少自动生成一些谓词:

std::vector<X> x = /**/;
std::vector<Y> y = /**/;

assert(x.size() == y.size());

//
// STL-way
//
struct Predicate: std::binary_function<X,Y,Y>
{
  Y operator()(X lhs, Y rhs) const { return rhs + f(lhs); }
};

std::transform(x.begin(), x.end(), y.begin(), y.begin(), Predicate());

//
// C++0x way
//
std::transform(x.begin(), x.end(), y.begin(), y.begin(),
               [](X lhs, Y rhs) { return rhs += f(lhs); });

Now, if we had a vector with the range of indices, we could do it in a more "pythony" way: 现在,如果我们有一个具有索引范围的vector ,我们可以用更“pythony”的方式来做:

std::vector<size_t> indices = /**/;


//
// STL-way
//
class Predicate: public std::unary_function<size_t, void>
{
public:
  Predicate(const std::vector<X>& x, std::vector<Y>& y): mX(x), mY(y) {}
  void operator()(size_t i) const { y.at(i) += f(x.at(i)); }
private:
  const std::vector<X>& mX;
  std::vector<Y>& mY;
};

std::foreach(indices.begin(), indices.end(), Predicate(x,y));

//
// C++0x way
//
std::foreach(indices.begin(), indices.end(), [&](size_t i) { y.at(i) += f(x.at(i)); });

//
// Boost way
//
BOOST_FOREACH(size_t i, indices) y.at(i) += f(x.at(i));

I don't know if there could be something to do with views, they normally allow some pretty syntax. 我不知道是否可能与视图有关,它们通常允许一些漂亮的语法。 Of course it's a bit difficult here I think because of the self-modifying y . 当然,这是一个有点困难在这里,我想这是因为自修改的y

Disclaimer : I have no practical experience with valarray, so please don't take this answer as an "advice", but more as a "request for comments". 免责声明 :我对valarray没有实际经验,所以请不要将此答案视为“建议”,而应将其作为“评论请求”。 In particular, I have no idea of how efficient this would be. 特别是,我不知道这会有多高效。 But I'm curious as the notation seems pretty intuitive to me: 但我很好奇,因为符号对我来说似乎很直观:

With x and y being valarray<int> and with a function int f(int) , would: 如果x和y是valarray<int>并且函数为int f(int) ,则会:

y += x.apply(&f);

do what you want? 做你想要的?

What is wrong with a simple loop? 简单循环有什么问题?

for (size_t i = 0; i < n; ++i)
  y[i] += f(x[i]); 

In general even in Fortran it would be: 一般来说,即使在Fortran中它也会是:

forall(i=0:n) y(i) += f(x(i))

Though with restrictions on f , x , y it could be written as: 虽然对fxy有限制,但可以写成:

y += f(x)

transform() variant is more generic and verbose: transform()变体更通用,更冗长:

std::transform(boost::begin(y), boost::end(y), boost::begin(x), 
               boost::begin(y), _1 += bind(f, _2)); 

It might be possible to write zip() using boost::zip_iterator : 也许可以使用boost::zip_iterator编写zip()

foreach (auto v, zip(y, z)) 
  v.get<0>() += f(v.get<1>());

where foreach is BOOST_FOREACH . 其中foreachBOOST_FOREACH

Here's variant similar to @Matthieu M.'s indices : 这里的变体类似于@Matthieu M.的指数

foreach (size_t i, range(n)) // useless compared to simple loop
  y[i] += f(x[i]); 

Possible range() Implementation 可能的range()实施

template<class T, class T2>
std::pair<boost::counting_iterator<T>, 
          boost::counting_iterator<T> > 
range(T first, T2 last) {
  return std::make_pair(boost::counting_iterator<T>(first), 
                        boost::counting_iterator<T>(last));
}

template<class T>
std::pair<boost::counting_iterator<T>, 
          boost::counting_iterator<T> > 
range(T last) {
  return range<T>(0, last);
}

Draft (broken) zip() Implementation 草稿(破损) zip()实现

template<class Range1, class Range2>
struct zip_return_type {
  typedef boost::tuple<
    typename boost::range_iterator<Range1>::type,
    typename boost::range_iterator<Range2>::type> tuple_t;

  typedef std::pair<
    boost::zip_iterator<tuple_t>,
    boost::zip_iterator<tuple_t> > type;
};

template<class Range1, class Range2>
typename zip_return_type<Range1, Range2>::type
zip(Range1 r1, Range2 r2) {
  return std::make_pair(
    boost::make_zip_iterator(
      boost::make_tuple(boost::begin(r1), boost::begin(r2))),
    boost::make_zip_iterator(
      boost::make_tuple(boost::end(r1), boost::end(r2))));
}

You have two ways. 你有两种方法。 I suppose y is some kind of your own container following the iterator idea. 我想y某种自己的容器下面的iterator的想法。

The first way is to write another routine that takes y , x and some functor as a param. 第一种方法是编写另一个以yx和一些仿函数作为参数的例程。 Generally it would do the same y[i] += f(x[i]) stuff, but if you name it correctly, this would make your code cleaner and easier to understand. 通常它会做同样的y[i] += f(x[i])东西,但如果你正确命名,这将使你的代码更清晰,更容易理解。

Another way is operator += (or + , or better together) overloading so that (let's say y has a container type) it would look the following way: 另一种方法是运算符+= (或+ ,或更好地一起)重载,以便(假设y有一个container类型)它将看起来如下:

container& operator+ (functor_type& functor)

Here your functor should be a struct / class declared the following way: 这里你的仿函数应该是一个以下面的方式声明的结构/类:

class functor {
private:
   container c;
public:
   functor (container& c) : c(c) { }
   container operator() (void) { (...) - your actions on container here }
};

This way you could write y += f(x) and it would be ok. 这样你就可以写y += f(x) ,就可以了。 However, I wouldn't recommend this way of managing your code, because all these operator overloads on your own datatypes generally make the code harder to understand. 但是,我不推荐这种管理代码的方法,因为在您自己的数据类型上所有这些运算符重载通常会使代码更难理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM