[英]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: 虽然对
f
, x
, y
有限制,但可以写成:
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
. 其中
foreach
是BOOST_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]);
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);
}
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. 第一种方法是编写另一个以
y
, x
和一些仿函数作为参数的例程。 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.