C++ ranges是否支持views::flat?与JS数组扁平化对比
C++ Ranges 实现数组扁平化问题解答
1. 扁平化vector<vector<int>>的管道函数
针对你提到的vector<vector<int>>扁平化需求,C++20 Ranges库提供的是**std::views::join**(不存在views::flat这个名称的适配器),代码可修改为:
#include <vector> #include <ranges> int main() { const std::vector<std::vector<int>> vv = {{0,1},{2,3}}; auto rg = vv | std::views::join; // 遍历rg会依次得到0、1、2、3 for (int num : rg) { // 处理元素逻辑 } }
std::views::join的作用就是将嵌套范围(如容器的容器)展开为单层元素序列,完全满足该场景需求。
2. 类似JavaScript flat(n)的多层嵌套扁平化
JavaScript的flat(n)支持指定嵌套深度,且因JS数组可存储混合类型,能处理[0,[1,[2,3]]]这类不同深度的混合嵌套结构,但C++是静态类型语言,无法直接处理混合类型的嵌套容器(除非借助std::variant或多态,但逻辑复杂度远高于JS的动态特性)。
固定深度的同类型嵌套
如果是固定深度的同类型嵌套(如vector<vector<vector<int>>>),可通过多次调用views::join实现对应深度的扁平化:
#include <vector> #include <ranges> int main() { const std::vector<std::vector<std::vector<int>>> vvv = {{{0}, {1}}, {{2,3}}}; // 扁平化2层,得到单层int序列 auto rg = vvv | std::views::join | std::views::join; }
任意深度的递归扁平化
C++标准库没有直接提供类似flat(Infinity)的递归扁平化视图,但可自定义递归范围适配器,核心逻辑是判断元素是否为可迭代范围,若是则递归展开,否则直接输出元素(仅支持同类型嵌套):
#include <vector> #include <ranges> #include <concepts> #include <iterator> namespace my_views { template<std::ranges::input_range R> requires (!std::same_as<std::ranges::range_value_t<R>, R> && std::ranges::input_range<std::ranges::range_value_t<R>>) struct recursive_join_view : std::ranges::view_interface<recursive_join_view<R>> { R base_; recursive_join_view(R base) : base_(std::move(base)) {} struct iterator { using base_iterator = std::ranges::iterator_t<R>; using inner_iterator = std::ranges::iterator_t<std::ranges::range_value_t<R>>; using value_type = std::ranges::range_value_t<std::ranges::range_value_t<R>>; base_iterator base_it_; base_iterator base_end_; inner_iterator inner_it_; inner_iterator inner_end_; iterator(base_iterator it, base_iterator end) : base_it_(it), base_end_(end) { if (base_it_ != base_end_) { auto& inner_range = *base_it_; inner_it_ = std::ranges::begin(inner_range); inner_end_ = std::ranges::end(inner_range); advance_to_valid(); } } void advance_to_valid() { while (base_it_ != base_end_ && inner_it_ == inner_end_) { ++base_it_; if (base_it_ != base_end_) { auto& inner_range = *base_it_; inner_it_ = std::ranges::begin(inner_range); inner_end_ = std::ranges::end(inner_range); } } } value_type& operator*() const { return *inner_it_; } iterator& operator++() { ++inner_it_; advance_to_valid(); return *this; } bool operator==(const iterator& other) const { return base_it_ == other.base_it_ && (base_it_ == base_end_ || inner_it_ == other.inner_it_); } }; iterator begin() { return iterator(std::ranges::begin(base_), std::ranges::end(base_)); } iterator end() { return iterator(std::ranges::end(base_), std::ranges::end(base_)); } }; struct recursive_join_adaptor { template<std::ranges::input_range R> requires std::ranges::input_range<std::ranges::range_value_t<R>> auto operator()(R&& r) const { return recursive_join_view<std::views::all_t<R>>(std::views::all(std::forward<R>(r))); } }; inline constexpr recursive_join_adaptor recursive_join; } // 使用示例 int main() { std::vector<std::vector<std::vector<int>>> vvv = {{{0}, {1}}, {{2,3}}}; auto rg = vvv | my_views::recursive_join; }
注意:该自定义适配器仅支持同类型嵌套,无法处理JS那样的混合类型数组。
总结
- 单层嵌套容器(如
vector<vector<int>>):使用标准库std::views::join即可,无views::flat适配器。 - 固定深度同类型嵌套:多次调用
views::join实现对应深度扁平化。 - 任意深度递归扁平化:标准库无直接支持,需自定义范围适配器,且仅能处理同类型嵌套结构。
内容的提问来源于stack exchange,提问作者Ludovic Aubert
相关产品推荐
相关产品推荐

