C++是否存在仅保留最先插入元素的std::unordered_map变体?
C++ std::unordered_map 重复键保留首次插入值的实现方案
内置原生方案(无需额外开发)
你要求的「重复键插入时忽略新值、保留最早插入值」的逻辑本身就是std::unordered_map的默认行为,只要你选择正确的插入接口即可:
- 仅使用
insert()方法插入键值对,当目标键已存在时,插入操作会直接被忽略,返回值的第二个字段为false表示插入失败 - 完全兼容原生
std::unordered_map的所有接口,你已经编写的遍历、打印代码不需要做任何修改 - 如果你需要的是只要哈希值重复就判定为重复元素,自定义哈希函数和相等比较函数即可,让相等比较逻辑和哈希值是否一致保持对齐。
示例代码:
#include <unordered_map> #include <string> #include <iostream> int main() { std::unordered_map<int, std::string> umap; // 首次插入成功 umap.insert({1, "first_insert"}); // 重复键插入,直接被忽略 auto insert_res = umap.insert({1, "later_insert"}); // 输出:first_insert,保留首次插入值 std::cout << insert_res.first->second << std::endl; return 0; }
注意:不要使用
operator[]、insert_or_assign接口,这两个接口会直接覆盖已存在的键对应的值。
高效后处理方案
如果你已经有一批待去重的键值对数据,需要保留首次出现的键对应的值,直接按原始顺序依次调用insert()插入到std::unordered_map即可:
- 平均时间复杂度为O(n),是当前场景下最高效的去重方案,无需额外排序操作
- 处理完成后的容器完全符合
std::unordered_map的接口规范,可直接传入你已有的遍历打印逻辑使用。
可选安全封装
如果担心误调用覆盖类接口导致值被修改,可以对std::unordered_map做一层薄封装,隐藏覆盖类接口,仅开放符合需求的操作:
template <class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = std::allocator<std::pair<const Key, T>>> class KeepFirstUnorderedMap : private std::unordered_map<Key, T, Hash, KeyEqual, Allocator> { using Base = std::unordered_map<Key, T, Hash, KeyEqual, Allocator>; public: // 开放所有原有非覆盖类接口,遍历、查找、删除逻辑完全和原生一致 using Base::begin; using Base::end; using Base::cbegin; using Base::cend; using Base::find; using Base::contains; using Base::erase; using Base::size; using Base::empty; // 仅开放不覆盖旧值的插入接口 std::pair<typename Base::iterator, bool> insert(const typename Base::value_type& val) { return Base::insert(val); } std::pair<typename Base::iterator, bool> insert(typename Base::value_type&& val) { return Base::insert(std::move(val)); } };
该封装类的迭代器类型和原生std::unordered_map完全一致,已有的遍历代码无需修改即可使用。
内容的提问来源于stack exchange,提问作者Ian Chiang
相关产品推荐
相关产品推荐

