按价值搜索地图

时间:2012-11-27 10:53:10

标签: c++ map

我有2个元素(现在)map:

#define IDI_OBJECT_5001 5001
#define IDI_OBJECT_5002 5002
    /.../


ResourcesMap[IDI_OBJECT_5001] = "path_to_png_file1";
ResourcesMap[IDI_OBJECT_5002] = "path_to_png_file2";

我正在尝试实现搜索此地图的方法。我正在传递字符串参数(文件路径)和方法返回int(映射的键值)

int ResFiles::findResForBrew(string filePath)
{
string value = filePath;
int key = -1;
for (it = ResourcesMap.begin(); it != ResourcesMap.end(); ++it)
{
    if (/*checking if it->second == value */)
    {
        key = it->first;
        break;
    }
}
return key;
}

类ResFiles {         上市:     ResFiles();     〜ResFiles();

map <int, string> ResourcesMap;
map <int, string>::const_iterator it;
void filenamesForBrew();
int findResForBrew(string filePath);

    private:

};

我如何检查它 - >&gt; second-&gt; == value,然后返回那个键? 我会感激一些帮助。提前谢谢。

4 个答案:

答案 0 :(得分:2)

这是一个基本的实现

 template <typename K, typename V>
     K keyFor(std::map<K, V> const& map, V const& target)
     {
         for (typename std::map<K, V>::const_iterator it=map.begin(); it!=map.end(); ++it)
             if (it->second == target)
                return it->first;

         return K(); // or throw?
     }

或者,支持C ++ 11:

         for (auto& pair : map)
             if (pair.second == target)
                return pair.first;

答案 1 :(得分:1)

你正在做什么应该工作,(只是it->second ==value)虽然如果你想要一个“有效”的查找键值,你应该创建第二张地图。

有些std::find这样的算法需要一个特殊的谓词,但它们只是在下面使用一个循环并且效率不高,因为搜索仍然是线性的。

如果你想做很多事情(如果你是......那就问你的设计)并想要一个特殊的模板,你可以:

template< typename K, typename V >
bool findByValue( std::map<K,V> const& theMap, K& key, const V& value )
{
    typename std::map<K,V>::const_iterator iter;
    for( iter it = theMap.begin(), itEnd = theMap.end(); it != itEnd; ++it )
    {
        if( it->second == value )
        {
            key = iter->first;
            return true;
        }
    }
    return false;
}

或者是std :: find_if

的自定义谓词
template< typename P > 
class Match2nd
{
   typedef typename P::second_type value_type;
   value_type val;

  public:

   explicit Match2nd( value_type const& v ) : val( v )
   {
   }

   bool operator()( P const& p ) const
   {
      return p.second == val;
   }
};

template< typename M > 
Match2nd< typename M::value_type >
makeMatch2nd( const M& map, typename M::mapped_type const& v )
{
    return Match2nd< M::value_type >( v );
}

然后在你的代码中你可以:

std::map< int, std::string >::const_iterator iter =
  std::find_if( ResourcesMap.begin(), ResourcesMap.end(), makeMatch2nd( value ) );

// if iter is end() the key doesn't exist, 
//if it does then iter->first is your key

你当然可以把它变成一个功能..

使用C ++ 0x,您还可以将Match2nd放入lambda并放入std :: find。然而...

所有这些东西仍然是线性搜索。如果您的地图很大,请以其他方式放入地图或使用boost :: multi_index或类似地方。

答案 2 :(得分:0)

好的,我找到了:

int ResFiles::findResForBrew(string filePath)
{
string value = filePath;
int key = -1;
for (it = ResourcesMap.begin(); it != ResourcesMap.end(); ++it)
{
    if(it->second.compare(filePath) == 0)
    {
        key = it->first;
        break;
    }
}
return key;
}

答案 3 :(得分:0)

首先,如果你的Key是路径,为什么要按ID索引?

如果您要查看文件路径,请将其用作Key,对于地图的每个键,查找某个值会比迭代更快。

第二个,恕我直言我建议使用const值而不是#define s,#define s没有输入所以如果执行一些意外的数据转换会很麻烦,我是一个强大价值类型的忠实粉丝。

试试这个:

// The type of the ID of the Resources.
typedef int ObjectID;

// Current resources.
const ObjectID IDI_OBJECT_5001 = 5001;
const ObjectID IDI_OBJECT_5002 = 5002;

// The type of a map containing resources, you can assure that 
// a Resource ID would be stored, as you can see at the mapped type.
typedef std::map<const std::string, const ObjectID> idpath;

idpath ResourcesMap;

第三,我不鼓励使用map::operator[]插入值,调用此运算符创建对象,然后通过{{1}分配新值映射类型;更不用说如果对象已经存在,则被覆盖。因此,使用此运算符我认为您执行的操作多于使用operator=方法:

map::insert

所以,最后,在你的代码中做什么:

ResourcesMap.insert(idpath::value_type("path_to_png_file1", IDI_OBJECT_5001));
ResourcesMap.insert(idpath::value_type("path_to_png_file2", IDI_OBJECT_5002));

请记住,此算法假设您可以交换Key-Map对,否则,您需要迭代整个地图。