按值搜索地图

searching map by value

本文关键字:地图 搜索      更新时间:2023-10-16

我有两个元素(目前)映射:

#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:

};

我如何检查它->秒->==值,然后返回该键?如果能给我一些帮助,我将不胜感激。提前谢谢。

以下是的基本实现

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;

您所做的应该是有效的(仅为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或类似方式。

好的,我找到了:

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

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

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

第二,IMHO,我建议使用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;
}

记住,这个算法假设你可以交换你的密钥映射对,如果你不交换,你需要迭代整个映射。