如何使用Ranges/Range-v3将两列CSV读取为std::map<int,int>
实现方案
你现有代码的两个问题可以通过调整视图流水线逻辑一次性解决,核心改动点有两个:
- 放弃
join+chunk(2)的拍平再分组逻辑:这种写法会丢失行边界信息,一旦某行逗号数量不对就会出现跨行配对的错误,且chunk的分组大小是运行时参数,无法做长度校验 - 逐行完成拆分、类型转换后直接构造
std::pair<int,int>,最终直接转换为std::map即可
完整可运行代码
#include <boost/hof/lift.hpp> #include <iostream> #include <map> #include <range/v3/range/conversion.hpp> #include <range/v3/view/istream.hpp> #include <range/v3/view/transform.hpp> #include <range/v3/view/split.hpp> #include <string> #include <utility> using ranges::to; using namespace ranges::views; constexpr auto splitAtComma = [](auto const& r) { return r | split(','); }; constexpr auto rngToString = [](auto const& r) { return r | to<std::string>(); }; constexpr auto strToInt = BOOST_HOF_LIFT(std::stoi); // 逐行处理:拆分逗号 -> 转字符串 -> 转int -> 转为pair(自动校验每行正好2个元素) constexpr auto lineToPair = transform(splitAtComma) | transform(rngToString) | transform(strToInt) | to<std::pair<int, int>>(); int main() { auto lines = istream<std::string>(std::cin); // 所有pair直接转换为std::map<int,int> auto coordMap = lines | lineToPair | to<std::map<int, int>>(); // 验证输出 for (auto [k, v] : coordMap) { std::cout << k << ":" << v << '\n'; } }
关键说明
to<std::pair<int,int>>()会校验输入范围的元素个数恰好为2,长度不符合时会直接抛出ranges::bad_conversion异常,不会出现静默的跨行错配问题,相比chunk(2)的方案安全性高很多- 流水线最终输出的是
std::pair<int,int>的视图,ranges::to<std::map<int,int>>()可以直接将这类键值对范围转换为目标map类型,不需要额外处理嵌套结构 - 运行你给出的测试输入,程序会正确输出:
1:2 11:7 12:40
注:
std::map是有序关联容器,输出会自动按key升序排列
补充说明
如果你使用C23标准库自带的Ranges实现,标准库的std::ranges::to对pair和map的转换支持和range-v3逻辑一致;C20及更早版本没有该工具,直接使用range-v3的实现兼容性更好。
内容的提问来源于stack exchange,提问作者Enlico
相关产品推荐
相关产品推荐

