根据值查找map中的元素

Finding an element in map by its value

本文关键字:元素 map 查找      更新时间:2023-10-16

我正在创建一个HandleManager,其目的是简单地将Handle s(这是long long inttypedef)映射到string s。这样做的目的是,使用Handle的对象也可以通过string来识别,如果它有助于用户记住对象的话。在这种情况下,在这个地图中:

typedef std::unordered_map<Handle, std::string> HandleMap;

对中的两个类型都是键,因为它们可以用来标识任何东西。到目前为止,除了需要获得Handle的代码外,所有内容都已编译。这样做的目的是,当用户分配string时,如下所示:

handle("myHandle"); 

随机生成一个Handle,然后传递的string在前面的映射中与它配对。我现在想要的是能够根据传递的string获得与string配对的Handle:

Handle HandleManager::id(const std::string &name)
{
    HandleMap::iterator it = pHandles.find(name);
    if (it != pHandles.end())
        return it->first;
    return -1;
}

但是由于一些奇怪的原因,编译器报错了:

HandleManager.cpp:48:45: error: no matching function for call to ‘std::unordered_map<long long int, std::basic_string<char> >::find(const string&)’

在前面的映射中,string是值,Handle是键。那么我如何根据其中包含的值从unordered_map获得 ?

std::unordered_map::find操作的是键,而不是值。您可以使用std::find_if:

Handle HandleManager::id(const std::string &name)
{
    auto it = std::find_if(std::begin(pHandles), std::end(pHandles),
                           [](auto&& p) { return p->second == name; });
    if (it == std::end(pHandles))
        return -1;
    return it->first
}

请注意auto, std::begin, std::end和lambdas是c++ 11,而泛型lambdas是c++ 14,所以如果你坚持使用旧的编译器,请将它们替换掉。

可以使用成员函数find只搜索key。要搜索值,可以使用带有lambda函数的std::find_if(如果使用c++ 11),或者遍历映射(在以前的c++版本中是可以的):

for (HandleMap::const_iterator it = map.begin(); it != map.end(); ++it) {
  if (it->second == name) return it->first;
} 
// or value not found

另一方面,如果搜索值是一个非常常见的操作,您可能希望有两个映射:std::unordered_map<Handle, std::string>std::unordered_map<std::string, Handle>。在这种情况下,你必须确保在两个映射中执行插入、删除等操作,以保持它们的同步。

但是由于一些奇怪的原因,编译器报错了:

当然可以,find函数是用于按键查找的,而您没有这样做。

要找到一个值,你需要访问每个元素,直到找到它(或者使用双向映射,将值映射回键,例如Boost.Bimap)。

根据@TartanLlama(*)的回答:

Handle HandleManager::id(const std::string & name) {
    auto iter = std::find_if(std::begin(pHandles), std::end(pHandles),
            [& name](auto && pair) {
        return pair.second == name;
    });
    if (it == std::end(pHandles)) {
        return -1;
    }
    return it->first;
} 

(*):因为似乎不可能在注释中格式化代码。