如何向内层map传递比较器?嵌套map自定义内层排序实现疑问
你这里犯了一个对std::map比较器的典型误解——std::map的比较器是用来排序它的键(key)的,完全和值(value)无关。
先看你的内层map定义:
map<string, Rank, compareRank>
这个map的键是string类型,但你传入的compareRank比较器,它的operator()是接受两个Rank对象的。这在编译阶段就会直接报错,因为map要求比较器必须能接收两个键类型的参数(也就是两个string),而你的比较器根本做不到这一点。就算忽略编译错误,map也绝不会用这个比较器去比较值,所以你的需求“根据Rank的rank值排序内层map”从根源上就走不通。
接下来给你两种实用的解决方案,根据你的实际场景选择:
方案一:用std::set存储键值对,自定义比较器按值排序
如果你的内层容器需要始终保持按Rank的rank值排序,可以用std::set来存储std::pair<string, Rank>,然后自定义比较器去比较pair中的Rank对象:
#include <set> #include <string> #include <map> #include <iostream> struct Rank { Rank() = default; int rank = 0; bool condition = false; }; // 自定义比较器:优先按Rank的rank值排序,rank相同时按string键排序(避免set重复元素) struct CompareByRank { bool operator()(const std::pair<std::string, Rank>& lhs, const std::pair<std::string, Rank>& rhs) const { if (lhs.second.rank != rhs.second.rank) { return lhs.second.rank < rhs.second.rank; } return lhs.first < rhs.first; } }; int main() { std::map<int, std::set<std::pair<std::string, Rank>, CompareByRank>> db; // 插入示例数据 db[1].insert({"Alice", {3, true}}); db[1].insert({"Bob", {1, false}}); db[1].insert({"Charlie", {2, true}}); // 遍历输出,会按rank从小到大排序 for (const auto& entry : db[1]) { std::cout << entry.first << ": " << entry.second.rank << std::endl; } // 输出顺序:Bob(1), Charlie(2), Alice(3) return 0; }
方案二:用普通map存储,遍历的时候按值排序输出
如果不需要容器始终保持排序,只是在需要展示的时候按rank值排列,那可以用普通的std::map<string, Rank>存储,然后在遍历前把元素提取到vector中,再自定义排序规则:
#include <vector> #include <algorithm> #include <map> #include <string> #include <iostream> struct Rank { Rank() = default; int rank = 0; bool condition = false; }; int main() { std::map<int, std::map<std::string, Rank>> db; // 插入示例数据 db[1]["Alice"] = {3, true}; db[1]["Bob"] = {1, false}; db[1]["Charlie"] = {2, true}; // 把内层map的元素提取到vector中 std::vector<std::pair<std::string, Rank>> sorted_vec(db[1].begin(), db[1].end()); // 按Rank的rank值排序 std::sort(sorted_vec.begin(), sorted_vec.end(), [](const auto& lhs, const auto& rhs) { return lhs.second.rank < rhs.second.rank; }); // 输出排序后的结果 for (const auto& entry : sorted_vec) { std::cout << entry.first << ": " << entry.second.rank << std::endl; } // 输出顺序:Bob(1), Charlie(2), Alice(3) return 0; }
额外说明
如果你坚持要用std::map来实现按值排序,那只能把Rank的rank作为键的一部分,但这样会有问题:如果两个不同的string对应相同的rank,后插入的会覆盖前一个(因为map的键是唯一的)。这种情况下可以用std::multimap<int, std::pair<string, Rank>>,但这样键是rank,你需要额外处理string的唯一性,不如前面两种方案实用。
内容的提问来源于stack exchange,提问作者alekscooper

