c++ - 在 range-v3 管道中插入一系列自定义元素的正确方法是什么?
问题描述
假设(这只是一个例子)我想使用 range-v3 库来创建一个序列,比如这个:
2 3 7 20 30 70 200 300 700 2000 3000 7000 ...
基本上,对于i
我从我那里获得的每一个,iota(0)
我都想将一个序列2*10^i, 3*10^i, 7*10^i
插入到管道中以进行进一步处理:
#include <cmath>
#include <iostream>
#include <range/v3/all.hpp>
int main(){
using namespace ranges::views;
auto rng = iota(0) |
/*
insert 2*10^i, 3*10^i, 7*10^i
*/ |
take_while([](int x){ return x < 10000;});
for(auto i: rng) {
std::cout << i << " ";
}
std::cout << "\n";
}
我不确定如何正确实施。我设法通过返回临时容器来创建一个工作示例,如本答案中所述:
#include <cmath>
#include <iostream>
#include <range/v3/all.hpp>
int main(){
using namespace ranges::views;
auto rng = iota(0) |
transform([](int i) {
int mul = pow(10, i);
return std::array{2*mul, 3*mul, 7*mul};
}) |
cache1 |
join |
take_while([](int x){ return x < 10000;});
for(auto i: rng) {
std::cout << i << " ";
}
std::cout << "\n";
}
但我想知道我是否可以更直接地做到这一点。事实上,ranges::views::for_each
听起来很合适(因为它会自动展平返回的范围),但我不确定要从中返回什么:
auto rng = iota(0) |
for_each([](int i){
int mul = pow(10, i);
return /* ?????????????????????????? */
}) |
take_while([](int x){ return x < 10000;});
或者也许有更惯用的方式在管道中插入自定义元素?
解决方案
我的一个想法是编写自己的视图,将传入的数据存储在std::initializer_list
private中std::vector
:
#include <vector>
template <typename T>
class store_view: public ranges::view_facade<store_view<T>> {
friend ranges::range_access;
std::vector<T> data_;
size_t pos_;
T const & read() const { return data_[pos_]; }
bool equal(ranges::default_sentinel_t) const { return data_.size() == pos_; }
void next() { ++pos_; }
public:
store_view() = default;
explicit store_view(std::initializer_list<T> data): data_{data}, pos_{0} {
}
};
在管道中使用这个视图看起来很整洁:
auto rng = iota(0) |
for_each([](int i){
int mul = pow(10, i);
return store_view{2*mul, 3*mul, 7*mul};
}) |
take_while([](int x){ return x < 10000;});
它有效,但似乎代价高昂,因为它为流中的每个值创建了一个新向量。一种不太漂亮但更有效的方法是只创建一次包含,然后在 lambda 中通过引用捕获它(因为它需要比它更长寿),更新它并使用以下方法作为视图返回ranges::views::all
:
std::array<int, 3> values;
auto rng = iota(0) |
for_each([&values](int i){
int mul = pow(10, i);
values[0] = 2*mul;
values[1] = 3*mul;
values[2] = 7*mul;
return values | all;
}) |
take_while([](int x){ return x < 10000;});
仍然不确定是否有更好的方法。
推荐阅读
- python - 如何根据每个子列表的第一个条目中的值将列表的 python 列表拆分为 3 个单独的列表?
- spring - Spring Batch - 如何将从 CSV 读取的行存储到可重新启动的执行上下文中
- opencv - 安装后导入opencv时Jupyter Notebook出错:libGL.so.1:无法打开共享对象文件:没有这样的文件或目录
- python - rpy2 内联图显示 Jupyter Notebook 中损坏的 UTF 标签
- amazon-cloudfront - 在 AWS Cloudfront 中,如何仅使主页无效?
- android - Android - 约束布局 - 边距与 layout_constraintWidth_percent
- excel - 数字与列表之间的复杂相似匹配
- python - 如何在python中转换字典中的多个列表
- mysql - 如何使用另一个表中的新列更新现有表?
- visual-studio-code - 更新 vscode v1.53 后 vscode Prettier 不工作