如何在 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 号码(假设没有一个名字被超过一个人使用),我将声明一个名为 Person
的 struct
并定义一个包含 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;
我有一个问题,关于如何在具有结构的 std::map
中找到具有至少一个数据编号等于正在搜索的键的对应元素。
例如,假设我要在 phone 本书中查找姓名为 或 的人的 phone 号码(假设没有一个名字被超过一个人使用),我将声明一个名为 Person
的 struct
并定义一个包含 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;