使用ranges::views::chunk_by时能否引用当前子范围并实现限长递增分块?
解决方案
你的核心问题是ranges::views::chunk_by的谓词只能访问相邻元素,无法跟踪当前块的大小,所以没法直接在谓词里同时满足「连续递增1」和「块大小不超过4」两个条件。下面提供两种基于Ranges库的实现方式:
方法一:组合视图(推荐)
先把序列分割成最大的连续递增块,再将每个大块拆分为最多4个元素的子块,最后展平结果。这种方式无状态、符合Ranges组合式编程的设计理念,代码可读性和可维护性都更好:
#include <ranges> #include <vector> #include <iostream> int main() { std::vector<int> v = {1,2,3,4,5,6,8,9,10,11,12,15}; auto result = v | std::ranges::views::chunk_by([](int a, int b) { return a + 1 == b; }) | std::ranges::views::transform([](auto continuous_chunk) { return continuous_chunk | std::ranges::views::chunk(4); }) | std::ranges::views::join; // 输出验证 for (auto subrange : result) { for (int num : subrange) { std::cout << num << " "; } std::cout << "\n"; } }
逻辑拆解
chunk_by:将原序列分割为最大的连续递增1的块(比如示例中的[1,2,3,4,5,6]、[8,9,10,11,12]、[15]);transform+chunk(4):对每个大块进行二次分割,确保每个子块的大小不超过4;join:将嵌套的子块视图展平为一层,得到最终符合要求的分块结果。
方法二:带状态的分割谓词
如果希望一步完成分割,可以自定义带状态的谓词配合split_when实现,但这种方式的视图不支持多次遍历(状态会保留):
#include <ranges> #include <vector> #include <iostream> struct SplitRule { int current_chunk_size = 1; // 初始值为1,因为第一个元素已计入当前块 bool operator()(int prev, int curr) { // 元素不连续,分割并重置块大小 if (prev + 1 != curr) { current_chunk_size = 1; return true; } // 元素连续但当前块已达4个元素,分割并重置 if (current_chunk_size >= 4) { current_chunk_size = 1; return true; } // 元素连续且块大小未超限,增大块大小,不分割 ++current_chunk_size; return false; } }; int main() { std::vector<int> v = {1,2,3,4,5,6,8,9,10,11,12,15}; auto result = v | std::ranges::views::split_when(SplitRule{}); // 输出验证 for (auto subrange : result) { for (int num : subrange) { std::cout << num << " "; } std::cout << "\n"; } }
注意事项
- 该方法的视图只能遍历一次,因为
SplitRule中的current_chunk_size状态会在遍历过程中修改; - 如果需要多次遍历,每次都要创建新的
SplitRule实例。
内容的提问来源于stack exchange,提问作者Sungtaek Lim
相关产品推荐
相关产品推荐

