关联容器所需的比较器

Comparator needed for an associative container

我需要一个 std::set<std::pair<std::string, int>, Compare> 根据它们的 int 值(以相反的顺序)比较两对,如果它们的 int 值相同则根据它们的字符串值(以相同的顺序), 但如果它们的字符串相等,则这两对被视为相等 (无论它们的 int 值如何)。所以我想出的 Compare class 是:

struct Compare {
    bool operator()(const std::pair<std::string, int>& a, const std::pair<std::string, int>& b) const {
        if (a.first == b.first)
            return false;
        if (a.second > b.second)
            return true;
        if (a.second < b.second)
            return false;
        return a.first < b.first;   
    }
};

测试

std::set<std::pair<std::string, int>, Compare> s;
s.insert({"Apple", 3}); 
s.insert({"Apple", 5}); 

工作正常(只插入第一对)。但是

int main() {
    std::set<std::pair<std::string, int>, Compare> s;
    s.insert({"Ai", 14}); 
    s.insert({"Am", 14}); 
    s.insert({"F", 5}); 
    s.insert({"Apple", 3}); 
    s.insert({"Apple", 5}); 
}

显示同时插入了 {"Apple", 3}{"Apple", 5},我不明白为什么。我的 Compare class 中的逻辑错误是什么?它应该是什么?我考虑过使用 std::map<std::string, int, Compare>,但在这种情况下,比较器只能使用密钥类型 std::string,这不符合我的规格。

我也试过:

bool operator()(const std::pair<std::string, int>& a, const std::pair<std::string, int>& b) const {
    if (a.first < b.first || a.first > b.first) {
        if (a.second > b.second)
            return true;
        if (a.second < b.second)
            return false;
        return a.first < b.first;
    }
    return false;
}

还是没有得到我想要的结果

问题是第一次比较,就是不对。删除它即可。

在检查了您的要求后,我得出的结论是您比较对象的标准不符合严格的周排序要求。

假设您将以下对象插入到集合中:

std::pair<std::string, int> obj1 = {"F", 5};
std::pair<std::string, int> obj2 = {"Apple", 3};
std::pair<std::string, int> obj3 = {"Apple", 5};

s.insert{obj1); 
s.insert(obj2); 
s.insert(obj3); 

obj1 被添加,因为集合中没有其他东西可以比较。 obj2 也被添加,因为它与 obj1 比较不相等。然而。由于 obj1.second > obj2.second,集合中对象的顺序是:

obj1
obj2   

现在,我们来插入obj3obj3 < obj1 的计算结果为 true。因此,它被插入到 obj1 之前。将项目插入集合的逻辑是 obj3 永远不会与 obj2 进行比较。因此,您最终得到:

obj3
obj1
obj2   

std::set 中的比较不是这样工作的。它旨在提供从最小到最大的顺序。使用您的集合,您正在尝试进行 2 种不同类型的比较。

您可以先按整数值,再按字符串值排序。没问题。

但是如果 none 如果一个集合中的 2 个元素比另一个元素更小,则它们被认为是相等的。

当您执行第一个示例时,这两个元素恰好彼此相邻,因此将对它们使用比较函数,并且您的 a.first == b.first 个案例触发器和 none 个似乎比另一个小,所以它们被认为是相等的。

当你第二次尝试时,当你插入时 "Apple", 5 你的设置看起来像这样。

Ai 14
Am 14
F 5
Apple 3

Apple, 5 将在这里比较小于 Am 14 和大于 F 5 所以它永远不会与 Apple 3 进行比较,但它会被插入到两个元素然后它变大变小。由于 std::set 预计已按顺序排序,因此就 Compare 而言,超出的元素无关紧要。