确定地图是否包含键值?


256

确定STL映射是否包含给定键值的最佳方法是什么?

#include <map>

using namespace std;

struct Bar
{
    int i;
};

int main()
{
    map<int, Bar> m;
    Bar b = {0};
    Bar b1 = {1};

    m[0] = b;
    m[1] = b1;

    //Bar b2 = m[2];
    map<int, Bar>::iterator iter = m.find(2);
    Bar b3 = iter->second;

}

在调试器中检查它,看起来就像iter是垃圾数据。

如果我取消注释此行:

Bar b2 = m[2]

调试器显示b2{i = 0}。(我猜这意味着使用未定义的索引将返回具有所有空/未初始化值的结构?)

这些方法都不是那么好。我真正想要的是这样的界面:

bool getValue(int key, Bar& out)
{
    if (map contains value for key)
    {
        out = map[key];
        return true;
    }
    return false;
}

是否存在符合这些原则的东西?


Answers:


274

是否存在符合这些原则的东西?

否。使用stl map类,您::find()可以搜索地图,并将返回的迭代器与std::map::end()

所以

map<int,Bar>::iterator it = m.find('2');
Bar b3;
if(it != m.end())
{
   //element found;
   b3 = it->second;
}

显然,您可以根据需要编写自己的getValue()例程(在C ++中也没有理由使用out),但是我怀疑一旦掌握了使用习惯,std::map::find()您就不会浪费时间了。

另外,您的代码略有错误:

m.find('2');将在地图上搜索值为的键值'2'。IIRC C ++编译器将隐式地将'2'转换为int,这将导致'2'的ASCII码的数字值不是您想要的。

由于在此示例中,int您的键类型是您想要的搜索:m.find(2);


7
为何如此?find表示意图远胜于意图count。更过,count不返回该项目。如果您阅读了OP的问题,则他想检查是否存在,返回该元素。find做到这一点。count才不是。
艾伦(Alan)

如果(m.count(key))b3 = m [key]; //或其他方式
pconnell

61
我一直对设计整个stl API的人正在抽哪种杂草感到好奇。
陷阱

2
艾伦(Alan)我必须在这一点上同意@dynamic,必须定义一个迭代器,然后将其与end比较,这并不是说不存在某些东西的自然方法。在我看来,某种元素在地图中至少出现一次似乎更直接。计数是做什么的。
PiersyP

1
@Claudiu C ++ 20添加了这一点。
pooya13

330

只要地图不是多地图,最优雅的方法之一就是使用count方法

if (m.count(key))
    // key exists

如果元素确实存在于地图中,则计数将为1。


22
即使已经找到一个密钥,这也不会检查所有密钥吗?那可以很快就变得昂贵……
mmdanziger 2012年

35
如果在多张地图上使用,它将仅计数一个以上的键。
Andrew Prock

14
@mmdanziger不,它不会很昂贵:cplusplus.com/reference/map/map/count 计数的大小是对数的。
jgyou 2014年

28
密钥存在,然后呢?到那时,您通常希望获得它的价值,再进行一次其他搜索(例如使用operator[])。find为您提供.NET的TryGetValue语义,这几乎总是您(尤其是OP)想要的。
Ohad Schneider 2014年

2
@serine了解。请注意,如果发布中缺少键,则行为会有所不同,因为map [key]将返回新的默认构造的元素值。
Ohad Schneider

53

它已经存在,并且find的语法不完全相同。

if (m.find(2) == m.end() )
{
    // key 2 doesn't exist
}

如果要访问值(如果存在),可以执行以下操作:

map<int, Bar>::iterator iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

使用C ++ 0x和auto,语法更简单:

auto iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

我建议您习惯使用它,而不要尝试提出一种简化它的新机制。您也许可以减少一些代码,但是要考虑这样做的成本。现在,您已经引入了一个新功能,熟悉C ++的人将无法识别。

如果尽管有这些警告,仍然要实现此目的,则:

template <class Key, class Value, class Comparator, class Alloc>
bool getValue(const std::map<Key, Value, Comparator, Alloc>& my_map, int key, Value& out)
{
    typename std::map<Key, Value, Comparator, Alloc>::const_iterator it = my_map.find(key);
    if (it != my_map.end() )
    {
        out = it->second;
        return true;
    }
    return false;
}

38

我刚刚注意到,使用C ++ 20,我们将拥有

bool std::map::contains( const Key& key ) const;

如果map包含具有key的元素,则将返回true key


最后是一个讨论此功能的答案!(C ++ 20)
塞缪尔·拉斯奎尼亚

最后呢?谢谢,但是已经快两年了!;-)
kebs


4

检查的返回值findend

map<int, Bar>::iterator it = m.find('2');
if ( m.end() != it ) { 
  // contains
  ...
}

1

您可以使用以下代码创建getValue函数:

bool getValue(const std::map<int, Bar>& input, int key, Bar& out)
{
   std::map<int, Bar>::iterator foundIter = input.find(key);
   if (foundIter != input.end())
   {
      out = foundIter->second;
      return true;
   }
   return false;
}

我相信第6行应该是out = foundIter->second
Dithermaster 2014年

我修复了Kip的答案以正确显示out = foundIter->second而不是out = *foundIter
netjeff

1

简要总结一些其他答案:

如果您尚未使用C ++ 20,则可以编写自己的mapContainsKey函数:

bool mapContainsKey(std::map<int, int>& map, int key)
{
  if (map.find(key) == map.end()) return false;
  return true;
}

如果您想避免mapvs unordered_map与许多键和值类型的重载,可以将其设为template函数。

如果您使用的是Windows C++ 20或更高版本,则将有一个内置contains函数:

std::map<int, int> myMap;

// do stuff with myMap here

int key = 123;

if (myMap.contains(key))
{
  // stuff here
}

-1

如果要确定映射中是否存在键,可以使用map的find()或count()成员函数。在示例中使用的find函数将迭代器返回element或map :: end否则。在计数的情况下,如果找到,则计数返回1,否则返回零(否则返回)。

if(phone.count(key))
{ //key found
}
else
{//key not found
}

for(int i=0;i<v.size();i++){
    phoneMap::iterator itr=phone.find(v[i]);//I have used a vector in this example to check through map you cal receive a value using at() e.g: map.at(key);
    if(itr!=phone.end())
        cout<<v[i]<<"="<<itr->second<<endl;
    else
        cout<<"Not found"<<endl;
}

-1

Boost multindex可用于适当的解决方案。遵循解决方案不是一个很好的选择,但是在少数情况下,用户在初始化时分配默认值(如0或NULL)并要检查值是否已被修改,可能会有用。

Ex.
< int , string >
< string , int > 
< string , string > 

consider < string , string >
mymap["1st"]="first";
mymap["second"]="";
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
{
       if ( it->second =="" ) 
            continue;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.