如何按比例筛选std::ranges::equal_range返回的大范围内均匀分布元素?
从std::ranges::equal_range结果中均匀采样元素的实现方法
要从std::ranges::equal_range返回的大范围内均匀选取指定数量的元素,无需修改原范围,直接通过视图组合就能实现需求,核心思路是利用元素索引进行筛选:
方法1:线性步长采样
先计算采样步长,再通过std::views::enumerate获取元素索引,筛选出符合步长间隔的元素:
修改后的完整代码
#include <algorithm> #include <iostream> #include <ranges> #include <vector> float gen() { static float v=0.0f; v+=0.1f; return v; } int main() { const size_t some_huge_size=100; std::vector<float> values(some_huge_size); std::ranges::generate(values, gen); const int some_value_to_search = some_huge_size/10-1; auto range = std::ranges::equal_range(values,some_value_to_search,{},[](auto& v){ return int(v); }); const int in_range_i_need_only = 4; const auto range_size = std::ranges::distance(range); // 计算采样步长,避免除以0 const size_t step = (range_size <= in_range_i_need_only) ? 1 : range_size / in_range_i_need_only; // 生成采样视图:筛选索引为0, step, 2*step...的元素 auto sampled_range = range | std::views::enumerate | std::views::filter([step](auto&& pair) { return pair.first % step == 0; }) | std::views::values; std::ranges::for_each(sampled_range, [](auto& v) { std::cout << v << ", ";}); }
说明
std::views::enumerate为每个元素绑定一个从0开始的索引;filter保留索引是步长整数倍的元素;views::values剥离索引,还原为原元素的视图,直接传给std::ranges::for_each即可。
方法2:Bresenham算法优化采样(更均匀分布)
当范围大小无法被采样数量整除时,线性步长会导致末尾元素分布不均,用Bresenham算法可以让采样点更均匀:
替换采样逻辑的代码片段
// 替换sampled_range的生成逻辑 auto sampled_range = range | std::views::enumerate | std::views::filter([range_size, in_range_i_need_only](auto&& pair) { const auto idx = pair.first; return idx * in_range_i_need_only * 2 >= range_size * (2 * idx - 1); }) | std::views::values;
这个逻辑基于Bresenham直线算法原理,让采样点在整个范围内均匀分布,避免线性步长的偏差。
为什么slide_view/chunk_view不合适?
slide_view和chunk_view会生成连续的子范围,而我们需要的是离散的单个元素,直接用enumerate+filter的组合更贴合需求,无需额外处理子范围的元素提取。
预期输出(为便于阅读添加额外空格):
9.1, 9.3, 9.5, 9.7,
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

