[英]C++ boost or STL `y += f(x)` type algorithm
我知道我可以使用兩個輸入迭代器的變換來做y[i] += f(x[i])
。 然而,它似乎有點違反直覺,比循環更復雜。
有沒有更自然的方法來使用boost或Stl中的現有算法。 我找不到干凈的等價物。
這里是變換(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
謝謝
有幾種方法可以做到這一點。
如您所述,您可以將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); });
現在,如果我們有一個具有索引范圍的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));
我不知道是否可能與視圖有關,它們通常允許一些漂亮的語法。 當然,這是一個有點困難在這里,我想這是因為自修改的y
。
免責聲明 :我對valarray沒有實際經驗,所以請不要將此答案視為“建議”,而應將其作為“評論請求”。 特別是,我不知道這會有多高效。 但我很好奇,因為符號對我來說似乎很直觀:
如果x和y是valarray<int>
並且函數為int f(int)
,則會:
y += x.apply(&f);
做你想要的?
簡單循環有什么問題?
for (size_t i = 0; i < n; ++i)
y[i] += f(x[i]);
一般來說,即使在Fortran中它也會是:
forall(i=0:n) y(i) += f(x(i))
雖然對f
, x
, y
有限制,但可以寫成:
y += f(x)
transform()
變體更通用,更冗長:
std::transform(boost::begin(y), boost::end(y), boost::begin(x),
boost::begin(y), _1 += bind(f, _2));
也許可以使用boost::zip_iterator
編寫zip()
:
foreach (auto v, zip(y, z))
v.get<0>() += f(v.get<1>());
其中foreach
是BOOST_FOREACH
。
這里的變體類似於@Matthieu M.的指數 :
foreach (size_t i, range(n)) // useless compared to simple loop
y[i] += f(x[i]);
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()
實現 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))));
}
你有兩種方法。 我想y
某種自己的容器下面的iterator
的想法。
第一種方法是編寫另一個以y
, x
和一些仿函數作為參數的例程。 通常它會做同樣的y[i] += f(x[i])
東西,但如果你正確命名,這將使你的代碼更清晰,更容易理解。
另一種方法是運算符+=
(或+
,或更好地一起)重載,以便(假設y
有一個container
類型)它將看起來如下:
container& operator+ (functor_type& functor)
這里你的仿函數應該是一個以下面的方式聲明的結構/類:
class functor {
private:
container c;
public:
functor (container& c) : c(c) { }
container operator() (void) { (...) - your actions on container here }
};
這樣你就可以寫y += f(x)
,就可以了。 但是,我不推薦這種管理代碼的方法,因為在您自己的數據類型上所有這些運算符重載通常會使代碼更難理解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.