只是一个简短的问题:
是否有任何C ++ 11相当于Haskell的inits?
inits函数返回参数的所有初始段, 最短的。
我想做某事。像
reverse $ inits [1..10]
C ++ 11支持 std::reverse ,但我找不到某事。比如 std :: inits 。
List将在C ++中表示为 std :: vector 。
答案 0 :(得分:2)
我认为我的工作纯粹是功能性的:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(void) {
vector<int> nums = { 1,5,5,9,8,7,6 };
auto inits = accumulate(nums.begin()+1, nums.end(), // Iterate between second and last element
vector< vector<int> >{ vector<int>{nums.front()}}, // Initialize accumulator
[] (vector< vector<int> > &acc, int j) { // Lambda constructing further elements
auto tmp = acc.back();
tmp.push_back(j);
acc.push_back( tmp );
});
return 0;
}
Inits将是int的矢量向量。
没有(可见)循环的一切: - )
答案 1 :(得分:1)
对于随机访问范围(因为您提到std::vector
),一系列连续切片是可管理的。这也适用于前向和双向范围,但在计算距离时会产生额外的线性成本。使用Boost.Range:
#include <boost/range/irange.hpp>
#include <boost/range/adaptor/sliced.hpp>
#include <boost/range/adaptor/transformed.hpp>
namespace R = boost::adaptors;
template<typename Range>
using range_difference_t = typename boost::range_difference<Range>::type;
namespace functors {
template<typename Range>
struct slice {
using difference_type = range_difference_t<Range>;
Range* range;
explicit slice(Range& range)
: range(&range)
{}
boost::sliced_range<Range> operator()(difference_type index) const
{
return R::slice(*range, static_cast<difference_type>(0), index);
}
};
} // functors
template<typename Range>
using inits_type =
boost::transformed_range<
functors::slice<Range>,
const boost::integer_range<range_difference_t<Range>>
>;
// calling inits with rvalues is not supported on purpose
template<typename Range>
inits_type<Range> inits(Range& range)
{
using diff_t = range_difference_t<Range>;
return R::transform(
// use boost::size instead of distance to restrict
// inits to working efficiently on random-access ranges only
boost::irange(static_cast<diff_t>(0), boost::distance(range) + static_cast<diff_t>(1)),
functors::slice<Range> { range }
);
}
这个解决方案从C ++ 14中获益匪浅,让我们只需:
// same includes
template<typename Range>
auto inits(Range& range)
{
namespace R = boost::adaptors;
using diff_t = typename boost::range_difference<Range>::type;
return R::transform(
boost::irange(static_cast<diff_t>(0), boost::distance(range) + static_cast<diff_t>(1)),
[range = &range](diff_t i) { return R::slice(*range, static_cast<diff_t>(0), i); }
);
}
对于非切片解决方案(即精神上与Haskell版本更接近),这需要手工编写迭代器,并考虑“有趣”的生命周期。我不推荐它。