You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C++20/23 std::views构建嵌套unordered_map结构?

用C20/C23 Views优化单次遍历的分组逻辑

我需要对输入的example_t结构体执行computeResults计算,将结果存入unordered_map<string, unordered_map<string, results_t>>——以结构体的attribute0为外层键、attribute1为内层键关联计算结果。目前我用range实现的方案需要多次遍历输入容器stuff,但原for循环仅需遍历一次。想知道在C20/C23中,有没有更优的views/ranges实现方式?

相关代码定义

struct results_t {
    int someNum;
    string someString;
};

struct example_t {
    string attribute0;
    string attribute1;
};

results_t computeResults(const example_t& input) {
    return { 0, "A" };
}

原for循环实现(单次遍历)

vector<example_t> stuff = { {"Food", "Bread"}, {"Food", "Apple"}, {"Animal", "Cat"}, {"Animal", "Dog"} };
unordered_map<string, unordered_map<string, results_t>> container = {};

for (const auto& thing : stuff) {
    const auto result = computeResults(thing);
    if (!container.contains(thing.attribute0))
        container.insert({ thing.attribute0, {} });
    container.at(thing.attribute0).insert({ thing.attribute1, result });
}

当前range实现(多次遍历)

auto uniqueAttribute0 = stuff | views::transform([](const auto & thing) { return thing.attribute0; })
    | ranges::to<unordered_set<std::string>>();

auto v = uniqueAttribute0
    | views::transform([&](const auto& key0) {
            auto innermap = stuff | views::filter([&](const auto& thing){ return thing.attribute0 == key0;})
                | views::transform([](const auto& thing)
                    { return make_pair(thing.attribute1, computeResults(thing)); })
                | ranges::to<unordered_map<string, results_t>>();
            return make_pair(key0, innermap);
        })
    | ranges::to<unordered_map<string, unordered_map<string, results_t>>>();

优化方案:单次遍历的range实现

原for循环的单次遍历逻辑本身已经是效率最优的——只遍历一次输入,边计算边构建嵌套map。如果想用range/ranges库实现等价的单次遍历逻辑,可以借助折叠(fold)操作:

C++23 实现(用std::ranges::fold_left)

#include <ranges>
#include <functional>

auto container = std::ranges::fold_left(
    stuff,
    std::unordered_map<std::string, std::unordered_map<std::string, results_t>>{},
    [](auto&& map, const auto& thing) {
        auto result = computeResults(thing);
        // 利用operator[]自动创建不存在的内层map,简化代码
        map[thing.attribute0][thing.attribute1] = result;
        return std::forward<decltype(map)>(map);
    }
);

C++20 实现(用std::accumulate配合range迭代器)

C++20标准库没有ranges::fold_left,但可以用std::accumulate结合range的首尾迭代器实现:

#include <numeric>

auto container = std::accumulate(
    std::ranges::begin(stuff),
    std::ranges::end(stuff),
    std::unordered_map<std::string, std::unordered_map<std::string, results_t>>{},
    [](auto&& map, const auto& thing) {
        auto result = computeResults(thing);
        map[thing.attribute0][thing.attribute1] = result;
        return std::forward<decltype(map)>(map);
    }
);

说明

  • 上述两种range方案都只遍历一次stuff,和原for循环的时间复杂度、效率完全一致。
  • 用map[key0][key1]的写法比原循环更简洁,因为unordered_map的operator[]会自动插入默认构造的内层map(如果外层键不存在),省去了手动判断和插入的步骤。
  • 惰性求值的views更适合做数据转换、过滤等无状态操作,而构建嵌套map属于有状态的累积操作,fold/accumulate是更贴合场景的选择,没必要强行用views实现。

内容的提问来源于stack exchange,提问作者ZZZ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:58:15