如何在 std::map 中查找具有至少一个数据成员等于键的结构的元素

How to find an element in std::map with structures that has at least one data member equal to the key

我有一个问题,关于如何在具有结构的 std::map 中找到具有至少一个数据编号等于正在搜索的键的对应元素。

例如,假设我要在 phone 本书中查找姓名为 的人的 phone 号码(假设没有一个名字被超过一个人使用),我将声明一个名为 Personstruct 并定义一个包含 Person 个对象和 his/her phone个数(在std::string):

struct Person {
    std::string name;
    std::string id;
};

std::map<Person, std::string> phonebook;

正如我从 Internet 上搜索的那样,我知道该结构需要重载 ==< 运算符才能与 std::map 一起使用并实现它们:

bool operator==(const Person &person1, const Person &person2) {
    return person1.name == person2.name || person1.id == person2.id;
}

bool operator<(const Person &person1, const Person &person2) {
    return person1.id < person2.id;
}

我在重载的==运算符中使用了逻辑"or"(||)来实现phone号码可以通过人名查找的功能 id,而不是两者都需要。

我写了一些代码来测试这个功能:

// Add some entries
phonebook[{"Jack", "001"}] = "12345";
phonebook[{"Mike", "002"}] = "12346";
phonebook[{"Eric", "003"}] = "12347";

// Search by name
std::map<Person, std::string>::iterator iter = phonebook.find({"Jack", ""});
if (iter == phonebook.end())
    std::cout << "Cannot find the phone number for Jack" << std::endl;
else
    std::cout << "Jack's phone number is " << iter->second << std::endl;

// Search by id
iter = phonebook.find({"", "001"});
if (iter == phonebook.end())
    std::cout << "Cannot find the phone number for 001" << std::endl;
else
    std::cout << "001's phone number is " << iter->second << std::endl;

但是,我发现按id搜索很好用,但是按名字搜索就不行了。无论搜索什么名字,都找不到phone这个号码。上面的测试代码产生了以下输出:

Cannot find the phone number for Jack
001's phone number is 12345

而预期输出是

Jack's phone number is 12345
001's phone number is 12345

此外,如果我将实现重载 < 运算符的方式更改为

bool operator<(const Person &person1, const Person &person2) {
    return person1.name < person2.name; // change "id" to "name"
}

然后按名称搜索就可以了,但是按id搜索就不行了。

那么我怎样才能用 std::map 实现这个功能(用 his/her 名字 id 找到一个人的 phone 号码)?还是不能这样实现?

提前致谢!

std::map仅根据operator<定义。当且仅当 !(a < b)!(b < a) 时,两个映射条目才被视为相等。您的 operator== 在这里没有帮助,所有 find() 调用所做的就是找到具有您指定的 ID(或第二种情况下的姓名)的人,因为它只考虑 operator<.

更大的图景是 std::map::find 利用 std::map 的排序(通常实现为红黑树)来避免检查每个元素。如果名称和 ID 都参与您的搜索,此 属性 没有帮助,因为您无法判断匹配名称 是在树中任何给定节点之前还是之后- 你只知道 ID(或者,在第二种情况下,名称)。

除非你想实现一个 非常 花哨和复杂的方式将名称和 ID 组合到一个 sortable/searchable 字段中(不知道你会怎么做) ,您将必须检查每个元素。 std::find_if 为您做到这一点:

std::find_if(phonebook.begin(), phonebook.end(), [name, id](const std::pair<Person, std::string>& personAndNumber) {
  const Person& person = personAndNumber.first;
  return person.name == name || person.id == id;
});

正如@Max Langhof 指出的那样,您只能使用find() 在地图中搜索,因为地图是按键排序的。要使用值(在您的情况下为名称)进行搜索,您可以简单地迭代所有键。虽然这种方法效率不高,因为您必须搜索地图中的每条记录。

for (auto it = phonebook.begin(); it != phonebook.end(); it++)
{
    if (it->second == "001")
    {
        return it->first;
    }     
}

// If you reach here, then value was not found
std::cout << "Cannot find the phone number for 001" << std::endl;