2

我有 2 个元素(目前)地图:

#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 { public: ResFiles(); ~ResFiles();

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

    private:

};

我如何检查它何时->秒-> ==值,然后返回该键?我将不胜感激。提前致谢。

4

4 回答 4

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;
于 2012-11-27T11:00:27.530 回答
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 或类似方式放入地图。

于 2012-11-27T11:02:36.153 回答
0

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

如果您将按文件路径查找,将其用作 Key,它会比迭代映射的每个键查找某个值更快。

第二个,恕我直言,我建议使用 const 值而不是#defines,#defines 没有类型,因此如果执行一些意外的数据转换可能会很麻烦,我是强值类型的忠实粉丝。

尝试这个:

// 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[]插入值,调用这个操作符你正在创建一个对象,然后通过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));

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

const ObjectID ID_NULL = 0;

ObjectID ResFiles::findResForBrew(string filePath) const // note the const ;)
{
    ObjectID Result = ID_NULL;
    // Perform the built-in map find, better than iterate the whole map.
    idpath::const_iterator Found = ResourcesMap.find(filePath);

    if (Found != ResourcesMap.end())
    {
        Result = Found->second;
    }

    return Result;
}

请记住,此算法假设您可以交换您的 Key-Map 对,如果您不这样做,则需要迭代整个映射。

于 2012-11-27T11:49:00.557 回答
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;
}
于 2012-11-27T11:35:18.143 回答