【问题标题】:Finding an element in map by its value根据值在地图中查找元素
【发布时间】:2015-12-23 03:50:42
【问题描述】:

我正在创建一个HandleManager,其目的是简单地将Handles(这是long long inttypedef)映射到strings。目的是让使用Handle 的对象也可以通过strings 来识别,前提是它有助于用户记住该对象。在这种情况下,在这张地图中:

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 是键。那么如何根据其中包含的valueunordered_map获取key

【问题讨论】:

  • 也许你需要boost::bimap
  • 唉,你得自己写这样的函数。
  • 您不能使用std::unordered_map,唯一的方法是遍历所有条目。 IIRC boost 提供了一种类型,它也允许按值查找。

标签: c++ dictionary


【解决方案1】:

您可以使用成员函数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&lt;Handle, std::string&gt;std::unordered_map&lt;std::string, Handle&gt;。在这种情况下,您必须确保在两个映射中执行插入、删除等操作以保持同步。

【讨论】:

  • 谢谢,这就是我要找的!
  • 但是必须注意,因为键值必须通过反转映射中的值来确保没有冲突
【解决方案2】:

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
}

请注意,autostd::beginstd::end 和 lambdas 是 C++11,而通用 lambdas 是 C++14,因此如果您使用旧的编译器,请将它们替换掉。

【讨论】:

  • 您忘记捕获name。而p 是一对。所以它应该是: auto it = std::find_if(std::begin(pHandles), std::end(pHandles), [& name](auto && pair) { return pair.second == name; });
【解决方案3】:

但出于某种奇怪的原因,编译器会抱怨:

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

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

【讨论】:

    【解决方案4】:

    基于answer from @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;
    } 
    

    (*):因为在 cmets 中似乎无法格式化代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-20
      • 2022-01-25
      相关资源
      最近更新 更多