如何查找C ++ std :: map中是否存在给定键


449

我正在尝试检查给定键是否在地图中,但有些无法做到:

typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here

所以我怎么打印p中的内容?


std::pair<iterator,bool> insert( const value_type& value );它返回的布尔值是多少?会告诉您密钥是否已经存在吗?
krithikaGopalakrisnan

Answers:


691

采用 map::find

if ( m.find("f") == m.end() ) {
  // not found
} else {
  // found
}

105
如果您只想检查某个键是否存在,则可能更愿意使用map::count
tomsmeding

10
@tomsmeding std :: map中只有一个键。因此,count将为0或1。一个效率比另一个高吗?
goelakash

34
@goelakash几乎没有;只是count返回int一会儿就find返回了整个迭代器。您可以保存迭代器的构造:)显然,如果以后要使用该值(如果存在),请使用find并存储其结果。
tomsmeding

9
@tomsmeding如果使用的是多图,则必须浏览整个容器。在这种情况下,find()可能会更快。
Trevor Hickey

11
对于那些谁是寻找速度: countfind使用需要独特的键地图时,在速度上几乎相同。(1)如果不需要元素来维持特定顺序,请使用std :: unordered_map,它具有近乎恒定的查找值,在存储多对时非常有用。(2)如果要使用该值(如果存在),请存储:: find的结果,并使用迭代器防止进行2次查找:auto it = m.find("f"); if (it != m.end()) {/*Use it->second*/}
cdgraham19年

305

要检查映射中是否存在特定键count,请通过以下方式之一使用成员函数:

m.count(key) > 0
m.count(key) == 1
m.count(key) != 0

文档map::find说:“其他部件的功能,map::count可以用来只检查一个特定的键是否存在。”

所述文档map::count表示:“因为在地图容器中的所有元素是唯一的,该函数只能返回1(如果该元件被发现),或零(否则)”。

要通过已知存在的键从映射中检索值,请使用map :: at

value = m.at(key)

map :: operator []不同map::at如果指定的键不存在,则不会在映射中创建新键。


33
如果要执行这两种操作,请检查它是否存在,然后对其进行处理。使用find代替。second返回的迭代器的属性find可用于检索键的值。如果您使用countthen atoperator[]执行两项操作,而您本可以只使用一项。
OdraEncoded 2014年

1
您不需要> 0,== 1或!= 0;这就是C ++在if语句(条件!= 0)中所做的确切检查,因此您可以使用if(m.count(key))
jv110 2016年

6
@ jv110微软C ++编译器发出警告,当它遇到一个演员是intbool。尽管还有其他C ++编译器没有发出类似的警告,但我更喜欢使用显式比较来使意图更清晰并增强可读性。请注意,其他语言(例如C#)禁止进行这种隐式转换,以防止引入细微的编程错误。
DavidRR

计数的时间复杂度是多少?只是O(1)运算吗?
马泽里特(Mazeryt)'17

1
@Mazeryt鉴于我们正在谈论的是C ++标准库中的类,所以我肯定会这么认为。有关您的问题的语言不可知的讨论,请参阅哈希表真的可以是O(1)吗?
DavidRR

47

C ++ 20使我们std::map::contains能够做到这一点。

#include <iostream>
#include <string>
#include <map>

int main()
{
    std::map<int, std::string> example = {{1, "One"}, {2, "Two"}, 
                                     {3, "Three"}, {42, "Don\'t Panic!!!"}};

    if(example.contains(42)) {
        std::cout << "Found\n";
    } else {
        std::cout << "Not found\n";
    }
}

33
我想我会说:最后。
Erik Campobadal

2
关于时间.....
Ridhuvarshan

39

您可以使用.find()

map<string,string>::iterator i = m.find("f");

if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }

14
m.find == m.end() // not found 

如果您想使用其他API,请找到go m.count(c)>0

 if (m.count("f")>0)
      cout << " is an element of m.\n";
    else 
      cout << " is not an element of m.\n";

12

我想你要map::find。如果m.find("f")等于m.end(),则找不到密钥。否则,find返回指向所找到元素的迭代器。

错误是因为p.first是一个迭代器,不适用于流插入。将最后一行更改为cout << (p.first)->first;p是一对迭代器,p.first是一个迭代器,p.first->first是密钥字符串。

映射对于给定的键只能有一个元素,因此equal_range不是很有用。它是为map定义的,因为它是为所有关联容器定义的,但是对于multimap来说,它要有趣得多。


实际上,因为它是映射的一对迭代器,所以它应该是“ cout << p.first-> first;”。
stefaanv

我已经确定答案,谢谢。这就是我不编译代码所得到的。而且,您对检查有效性是正确的(在删除的评论中),但是我只是想解释一下为什么他不能先打印p。,这不是因为它无效-我们知道将找到“ f”。由于我完全不建议使用equal_range,因此我不会显示对此的错误检查代码。
史蒂夫·杰索普

哇,您真的在扫描SO。我只是为了完整性而添加它,因为您的观点很明确。我将有效性检查添加到了先前的答案中,但是您的回答击败了我,所以我删除了它,因为它反正没有增加太多,就像您提到的那样。
stefaanv

是的,我只看到了它,因为您的评论是在我发布我的评论时出现的。
史蒂夫·杰索普

12

C++17通过进一步简化了此操作If statement with initializer。这样,您就可以吃蛋糕了。

if ( auto it{ m.find( "key" ) }; it != std::end( m ) ) 
{
    // Use `structured binding` to get the key
    // and value.
    auto[ key, value ] { *it };

    // Grab either the key or value stored in the pair.
    // The key is stored in the 'first' variable and
    // the 'value' is stored in the second.
    auto mkey{ it->first };
    auto mvalue{ it->second };

    // That or just grab the entire pair pointed
    // to by the iterator.
    auto pair{ *it };
} 
else 
{
   // Key was not found..
}

4
map<string, string> m;

检查密钥是否存在,并返回出现的次数(在地图中为0/1):

int num = m.count("f");  
if (num>0) {    
    //found   
} else {  
    // not found  
}

检查密钥是否存在,并返回迭代器:

map<string,string>::iterator mi = m.find("f");  
if(mi != m.end()) {  
    //found  
    //do something to mi.  
} else {  
    // not found  
}  

在您的问题中,错误是由错误的operator<<重载引起的,因为p.firstmap<string, string>,您无法将其打印出来。尝试这个:

if(p.first != p.second) {
    cout << p.first->first << " " << p.first->second << endl;
}

1
你有错字 将“ cout”更改为“ count”
Rivka

1
这种错别字确实可以把某人赶走,因为这cout可能意味着与count
-modulitos

4
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
    return (container.find(key) != std::end(container));
}

当然,如果您想变得更高级,可以随时将同时包含找到的功能和未找到的功能的函数模板化,如下所示:

template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
    auto& it = container.find(key);
    if (it != std::end(container))
    {
        found_function(key, it->second);
    }
    else
    {
        not_found_function(key);
    }
}

并像这样使用它:

    std::map<int, int> some_map;
    find_and_execute(some_map, 1,
        [](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
        [](int key){ std::cout << "key " << key << " not found" << std::endl; });

缺点是想出一个好名字,“ find_and_execute”很尴尬,我想不出更好的办法...


3

小心地将查找结果与末尾的结果进行比较,例如映射“ m”,因为所有答案均已在map :: iterator i = m.find(“ f”);上方完成。

 if (i == m.end())
 {
 }
 else
 {
 }  

如果它等于m.end(),则不应尝试执行任何操作,例如使用迭代器i打印键或值,否则将导致分段错误。


0

比较std :: map :: find和std :: map :: count的代码,我想说第一个可能会带来一些性能优势:

const_iterator find(const key_type& _Keyval) const
    {   // find an element in nonmutable sequence that matches _Keyval
    const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
    return (_Where == end()
        || _DEBUG_LT_PRED(this->_Getcomp(),
            _Keyval, this->_Key(_Where._Mynode()))
                ? end() : _Where);
    }

size_type count(const key_type& _Keyval) const
    {   // count all elements that match _Keyval
    _Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
    size_type _Num = 0;
    _Distance(_Ans.first, _Ans.second, _Num);
    return (_Num);
    }

0

我知道这个问题已经有了一些不错的答案,但是我认为我的解决方案值得分享。

它同时适用于std::mapstd::vector<std::pair<T, U>>并且可以从C ++ 11获得。

template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
    using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;

    auto search_result = std::find_if(
        first, last,
        [&key](ValueType const& item) {
            return item.first == key;
        }
    );

    if (search_result == last) {
        return false;
    } else {
        return true;
    }
}

-5

如果要比较一对地图,可以使用以下方法:

typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;

controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
    TestMap::iterator it;
    it = testMap.find(x);

    if (it->second == y)
    {
        cout<<"Given value is already exist in Map"<<endl;
    }
}

这是一种有用的技术。


作为C ++编程的初学者,我真的很好奇为什么这个答案被否决了。为什么这个答案不受欢迎?
gromit190

3
@ gromit190,因为当std :: map已经具有此功能时,它正在使用其他数据结构来查看密钥是否存在。这也将需要两个数据结构之间的同步,而这是没人希望处理的依赖项。
Lambage

-5
map <int , char>::iterator itr;
    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
    {
        if (itr->second == 'c')
        {
            cout<<itr->first<<endl;
        }
    }

3
请详细说明您的代码。从长远来看,没有任何解释的代码片段往往无济于事。
iBug
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.