【问题标题】:Checking value exist in a std::map - C++检查值存在于 std::map - C++
【发布时间】:2010-10-06 19:48:45
【问题描述】:

我知道 find 方法在 std::map 中找到提供的键并将迭代器返回到元素。反正有没有找到值并获得元素的迭代器?我需要做的是检查 std::map 中是否存在指定的值。我通过循环地图中的所有项目并进行比较来做到这一点。但我想知道有没有更好的方法。

这是我写的

bool ContainsValue(Type_ value)
{
    bool found = false;
    Map_::iterator it = internalMap.begin(); // internalMap is std::map
    while(it != internalMap.end())
    {
        found = (it->second == value);
        if(found)
            break;
        ++it;
    }
    return found;
}

编辑

如何在内部使用另一个存储值、键组合的地图。所以我可以调用 find 吗? std::map 中的 find() 是否进行顺序搜索?

谢谢

【问题讨论】:

    标签: c++ iterator find stdmap


    【解决方案1】:

    如果有人来这里寻找 c++11 及更高版本,我正在添加这个答案..

        //DECLARE A MAP
        std::map<int, int> testmap;
    
        //SAMPLE DATA
        testmap.insert(std::make_pair(1, 10));
        testmap.insert(std::make_pair(2, 20));
        testmap.insert(std::make_pair(3, 30));
        testmap.insert(std::make_pair(4, 20));
    
        //ELEMENTS WITH VALUE TO BE FOUND
        int value = 20;
    
        //RESULTS
        std::map<int, int> valuesMatching;
    
        //ONE STEP TO FIND ALL MATCHING MAP ELEMENTS
        std::copy_if(testmap.begin(), testmap.end(), std::inserter(valuesMatching, valuesMatching.end()), [value](const auto& v) {return v.second == value; });
    

    【讨论】:

      【解决方案2】:

      不是一个最好的选择,但在用户在初始化时分配默认值(如 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;
      }
      

      【讨论】:

        【解决方案3】:

        您所要求的正是 std::find 所做的(不是成员函数)

        template< class InputIt, class T >
        InputIt find( InputIt first, InputIt last, const T& value );
        

        【讨论】:

        • 非常简单的答案。除了如果经常这样做效率不高。
        【解决方案4】:

        试试这个功能:

        template <class Map, class Val> typename Map::const_iterator MapSearchByValue(const Map & SearchMap, const Val & SearchVal)
        {
            Map::const_iterator iRet = SearchMap.end();
            for (Map::const_iterator iTer = SearchMap.begin(); iTer != SearchMap.end(); iTer ++)
            {
                if (iTer->second == SearchVal)
                {
                    iRet = iTer;
                    break;
                }
            }
            return iRet;
        }
        

        我觉得很有用

        【讨论】:

        • 如果我错了,请纠正我,但这不只是问题中的代码吗?
        【解决方案5】:

        我可能不完全理解您要完成的工作。但是为了简单测试一个map是否包含值,我相信你可以使用find内置的std::map

        bool ContainsValue(Type_ value)
        {
            return (internalMap.find(value) != internalMap.end());
        }
        

        【讨论】:

        • std::map::find 按键搜索,他正在尝试按值搜索。
        • 你说得对。我想没有手动迭代和搜索地图,你应该使用像已经建议的 Boost.MultiIndex 这样的双向地图。
        【解决方案6】:

        如果您可以访问出色的 boost 库,那么您应该使用 boost::multi_index 创建 bidirectional map,正如 Mark 所说。与 std::map 不同,这允许您通过键或值进行查找。

        如果您只有 STL 来处理,下面的代码就可以解决问题(模板可用于 mapped_type 支持 operator== 的任何类型的地图):

        #include <map>
        #include <string>
        #include <algorithm>
        #include <iostream>
        #include <cassert>
        
        template<class T>
        struct map_data_compare : public std::binary_function<typename T::value_type, 
                                                              typename T::mapped_type, 
                                                              bool>
        {
        public:
            bool operator() (typename T::value_type &pair, 
                             typename T::mapped_type i) const
            {
                return pair.second == i;
            }
        };
        
        
        int main()
        {
            typedef std::map<std::string, int> mapType;
        
            mapType map;
        
            map["a"] = 1;
            map["b"] = 2;
            map["c"] = 3;
            map["d"] = 4;
            map["e"] = 5;
        
            const int value = 3;
        
            std::map<std::string, int>::iterator it = std::find_if( map.begin(), map.end(), std::bind2nd(map_data_compare<mapType>(), value) );
        
            if ( it != map.end() )
            {
                assert( value == it->second);
                std::cout << "Found index:" << it->first << " for value:" << it->second << std::endl;
            }
            else
            {
                std::cout << "Did not find index for value:" << value << std::endl;
            }
        }
        

        【讨论】:

          【解决方案7】:

          如何在内部使用另一个存储值、键组合的地图。所以我可以调用 find 吗?

          是的:维护两张地图,一张地图使用一种类型的键,另一张使用另一种。

          std::map 中的 find() 是否进行顺序搜索?

          不,这是对排序树的二分查找:它的速度是 O(log(n))。

          【讨论】:

          • 这是有道理的。那么维护两张地图会比顺序搜索和查找价值提供更好的性能,对吗?
          • 插入或删除任何东西都需要两倍的时间(使用两个映射而不是一个);但是对于大量元素,查找会快很多,因为 O(log(n)) 远小于顺序搜索所需的 O(n)。
          • 如此简单却又如此出色(尤其是在无法选择使用 boost 库时)。有我的赞成票。我想补充一点,对于反向映射,使用 std::multimap 可能比 std::map 更好,因为您的原始映射可以有重复的值。这些重复的值然后成为反向映射中的键,因此使用 std::map 会丢失数据。
          【解决方案8】:

          不,您必须遍历 std::map 并手动检查所有值。根据您要执行的操作,您可以将 std::map 包装在一个简单的类中,该类还将所有插入到映射中的值缓存在易于搜索且不允许重复的内容中,例如 std ::放。不要从 std::map 继承(它没有虚拟析构函数!),而是包装它以便您可以执行以下操作:

          WrappedMap my_map< std::string, double >;
          my_map[ "key" ] = 99.0;
          std::set< double > values = my_map.values(); // should give back a set with only 99.0 in it
          

          您自己的替代方法是使用 Boost 双向地图,您可以在下面的帖子中或通过 Google 轻松找到该地图。

          这真的取决于你想做什么,你想多久做一次,以及滚动你自己的小包装类与安装和使用 Boost 相比有多难。我喜欢 Boost,所以这是一个很好的方法 - 但是制作你自己的包装类有一些很好和完整的东西。您的优势在于可以直接了解操作的复杂性,并且您可能不需要 Boost 双向映射提供的值 => 键的完整反向映射。

          【讨论】:

          • 他想要一个元素的迭代器,所以你想使用第二个地图而不是一个集合。
          【解决方案9】:

          查看 boost 的双向地图:http://www.boost.org/doc/libs/1_38_0/libs/bimap/doc/html/index.html

          它让两个值都像一个键。

          否则,迭代是要走的路。

          【讨论】:

            【解决方案10】:

            您可以使用boost::multi_index 创建一个bidirectional map - 您可以使用该对的任一值作为键来进行快速查找。

            【讨论】:

              猜你喜欢
              • 2010-12-28
              • 2011-12-18
              • 2014-10-18
              • 1970-01-01
              • 2023-03-27
              • 2023-01-12
              • 1970-01-01
              • 2014-02-09
              相关资源
              最近更新 更多