【问题标题】:How to find if a given key exists in a C++ std::map如何查找给定键是否存在于 C++ std::map 中
【发布时间】:2010-12-28 17:42:48
【问题描述】:

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

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&lt;iterator,bool&gt; insert( const value_type&amp; value ); 它返回的布尔值是什么?它是否说明密钥是否已经存在?

标签: c++ dictionary stl


【解决方案1】:

使用map::find

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

【讨论】:

  • 如果你只是想检查某个键是否存在,你可能宁愿使用map::count
  • @tomsmeding std::map 中只有一个键。所以 count 要么是 0 要么是 1。一个比另一个更有效吗?
  • @goelakash 几乎没有;只是count 返回一个intfind 返回一个完整的迭代器。您保存了迭代器的构造 :) 显然,如果您之后要使用该值(如果存在),请使用 find 并存储其结果。
  • @tomsmeding 如果您使用的是多图,则必须查看整个容器。在这种情况下,find() 可能会更快。
  • 致追求速度的人countfind 在使用需要唯一键的地图时速度几乎相同。 (1) 如果您不需要元素保持特定顺序,请使用std::unordered_map,它具有near-constant 查找功能,并且在存储多对时非常有用。 (2)如果要使用该值,如果存在,存储::find的结果并使用迭代器防止2次查找:auto it = m.find("f"); if (it != m.end()) {/*Use it-&gt;second*/}
【解决方案2】:

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

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

map::finddocumentation 表示:“另一个成员函数 map::count 可用于检查特定键是否存在。”

map::countdocumentation 表示:“因为地图容器中的所有元素都是唯一的,所以该函数只能返回 1(如果找到该元素)或零(否则)。”

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

value = m.at(key)

map::operator[] 不同,map::at 不会在指定键不存在的情况下在映射中创建新键。

【讨论】:

  • 如果要同时执行这两个操作,请检查它是否存在,然后对其进行处理。请改用findfind 返回的迭代器的second 属性可用于检索键的值。如果您使用 count 然后使用 atoperator[] 您正在执行两个操作,而您只能使用一个。
  • 你不需要做 > 0, == 1 or != 0;这正是 C++ 在 if 语句中所做的检查(条件!= 0),所以你可以使用 if(m.count(key))
  • @jv110 Microsoft C++ 编译器issues a warning 在遇到从intbool 的转换时。尽管有其他 C++ 编译器不会发出类似的警告,但我更喜欢使用 explicit comparison 来明确意图并增强可读性。请注意其他语言如 C#forbid such an implicit conversion 以防止引入细微编程错误的可能性。
  • @Mazeryt 鉴于我们正在讨论 C++ 标准库中的一个类,我当然会这么认为。有关您的问题的与语言无关的讨论,请参阅Can hash tables really be O(1)?
  • @Mazeryt 不,std::map::count 实际上是logarithmic。这是因为C++ std::map 是有序映射,所以它不使用哈希表。但是,C++ 标准库也有std::unordered_map,其中std::unordered_map::countO(1) often。请参阅 DavidRR's link 以了解为什么即使 std::unordered_map::count 也不总是 O(1)。
【解决方案3】:

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";
    }
}

【讨论】:

  • 我想我会说:终于。
【解决方案4】:

你可以使用.find():

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

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

【讨论】:

    【解决方案5】:

    C++17If statement with initializer 简化了这一点。 这样你就可以吃蛋糕了。

    if ( auto it{ m.find( "key" ) }; it != std::end( m ) ) 
    {
        // Use `structured binding` to get the key
        // and value.
        const 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.
        const auto& mkey{ it->first };
        const auto& mvalue{ it->second };
    
        // That or just grab the entire pair pointed
        // to by the iterator.
        const auto& pair{ *it };
    } 
    else 
    {
       // Key was not found..
    }
    

    【讨论】:

      【解决方案6】:
      m.find == m.end() // not found 
      

      如果你想使用其他API,那就去m.count(c)&gt;0

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

      【讨论】:

        【解决方案7】:

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

        错误是因为p.first 是一个迭代器,它不适用于流插入。将最后一行更改为 cout &lt;&lt; (p.first)-&gt;first;p 是一对迭代器,p.first 是一个迭代器,p.first-&gt;first 是关键字符串。

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

        【讨论】:

        • 其实因为是map的一对迭代器,所以应该是"cout first;"
        • 我已经修正了我的答案,谢谢。这就是我不编译我的代码所得到的。你是对的(在已删除的评论中)检查有效性,但我只是想解释为什么他不能打印 p.first,这不是因为它无效 - 我们知道会找到“f”。由于我根本不建议使用 equal_range,因此我不打算为此显示错误检查代码。
        • 哇,你真的在​​扫描。我只是为了完整性而添加它,因为您的观点很清楚。我在之前的答案中添加了有效性检查,但您的回复击败了我,所以我删除了它,因为它并没有像您提到的那样添加那么多。
        • 是的,我只看到它,因为我发布我的评论时出现了您的评论。
        【解决方案8】:
        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”很尴尬,我想不出更好的名字......

        【讨论】:

          【解决方案9】:
          map<string, string> m;
          

          检查key是否存在,返回出现次数(map中的0/1):

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

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

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

          在你的问题中,错误operator&lt;&lt;重载导致的错误,因为p.firstmap&lt;string, string&gt;,所以不能打印出来。尝试这个:

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

          【讨论】:

          • 你有一个错字。将“cout”改为“count”
          • 这个错字真的会让人失望,因为cout 的含义可能与count 完全不同
          【解决方案10】:

          在将查找结果与地图“m”的结尾进行比较时要小心,因为所有答案都有 以上完成 map::iterator i = m.find("f");

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

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

          【讨论】:

            【解决方案11】:

            比较 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);
                }
            

            【讨论】:

              【解决方案12】:

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

              它适用于 std::mapstd::vector&lt;std::pair&lt;T, U&gt;&gt;,并且可从 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;
                  }
              }
              

              【讨论】:

                【解决方案13】:
                map <int , char>::iterator itr;
                    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
                    {
                        if (itr->second == 'c')
                        {
                            cout<<itr->first<<endl;
                        }
                    }
                

                【讨论】:

                • 请详细说明您的代码。从长远来看,没有任何解释的 sn-p 往往没有帮助。
                【解决方案14】:

                如果你想比较一对地图,你可以使用这个方法:

                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 因为当 std::map 已经具有此功能时,它正在使用整个其他数据结构来查看密钥是否存在。这还需要两个数据结构之间的同步,这是一种没人愿意处理的依赖关系。
                猜你喜欢
                • 1970-01-01
                • 2014-10-18
                • 2010-12-21
                • 2010-10-06
                • 2012-05-01
                • 1970-01-01
                • 2010-12-12
                • 2012-05-21
                相关资源
                最近更新 更多