如何遍历std::map并将满足断言的键值对移至另一个std::map
拆分std::map到另一个map的高效实现
一、基于键范围的断言(最高效)
如果你的断言可以转化为键的连续范围(比如键大于等于X、小于Y),直接利用std::map的有序特性,结合extract和merge操作,这是最优方案——完全不需要拷贝或移动元素,仅转移节点所有权:
#include <map> #include <string> int main() { std::map<int, std::string> m = {{1, "a"}, {5, "e"}, {7, "g"}, {10, "j"}}; std::map<int, std::string> m2; // 自定义断言:键 >=5 且键 <10 auto start = m.lower_bound(5); auto end = m.upper_bound(9); // 提取该范围的节点并合并到m2 m2.merge(m.extract(start, end)); }
复杂度:O(log n + k),k为移动的元素数量,几乎无额外开销
二、任意自定义断言(值/键值组合判断)
如果断言是任意条件(比如值的长度、内容,或键值的组合判断),可以用extract逐个处理满足条件的元素,避免拷贝开销:
#include <map> #include <string> int main() { std::map<int, std::string> m = {{1, "a"}, {2, "bb"}, {3, "c"}, {4, "ddd"}}; std::map<int, std::string> m2; auto it = m.begin(); while (it != m.end()) { // 自定义断言:值的长度大于1 if (it->second.size() > 1) { // 先递增迭代器,再提取节点(extract会使当前迭代器失效) m2.insert(m.extract(it++)); } else { ++it; } } }
注意:extract是C++17引入的特性,确保编译器支持该标准
兼容C++11/14的替代方案
如果无法使用C++17,可通过std::move转移元素,再从原map中删除:
#include <map> #include <string> #include <utility> int main() { std::map<int, std::string> m = {{1, "a"}, {2, "bb"}, {3, "c"}, {4, "ddd"}}; std::map<int, std::string> m2; auto it = m.begin(); while (it != m.end()) { if (it->second.size() > 1) { // 移动元素到m2,再删除原位置元素 m2.insert(std::move(*it)); it = m.erase(it); } else { ++it; } } }
该方案会触发元素的移动构造,效率略低于extract,但远优于拷贝
关键说明
- 避免直接遍历拷贝后erase:这种方式会产生不必要的元素拷贝,对于大容器或大类型(如长字符串),性能损耗明显。
extract和merge操作仅转移节点所有权,不涉及元素的构造/析构,是处理大容器的最优选择。
内容的提问来源于stack exchange,提问作者calvin
相关产品推荐
相关产品推荐

