文章目录
- 概要介绍
- find_if 函数
- 单独函数专门处理
- 参考文章附录
概要介绍
我们都熟知 STL 中模板库的std::map可以按key查找对应的值,有些应用中可能会出现 Value 也是唯一的需求状态,举例而言,如果Value中保存的是GUID等唯一性数值,那么key-value 对应关系就从1:N 变成了 1:1。
如果想要以key查找,那么find已经足够了,如果想按value查找,那就得研究下find_if函数了。
find_if 函数
template <class InputIterator, class Predicate>
InputIterator find_if(InputIterator first, InputIterator last,Predicate pred)
{
while (first != last && !pred(*first)) ++first;
return first;
}
template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last,
UnaryPredicate p );
template< class InputIt, class UnaryPredicate >
constexpr InputIt find_if( InputIt first, InputIt last,
UnaryPredicate p );
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt find_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last,
UnaryPredicate p ); 简单说就是 返回迭代器中first到last之间第一个使得pred函数返回true的 迭代器指针。
所以得自己实现一个比较函数
一种方式是实现一个类,类内提供一个value_type类型成员变量,实现构造函数,重载operator () --基本上这三个就足够了。如下:
class map_value_finder
{
public:
map_value_finder(QString &cmp_string):m_s_cmp_string(cmp_string){}
bool operator ()(const std::map<int, QString>::value_type &pair)
{
if ( pair.second.compare(m_s_cmp_string) == 0)
return true;
return false;
}
private:
const QString &m_s_cmp_string;
};使用的时候:
std::map<int, QString>::iterator iter = m_mapIndexToFileGuid.end();
iter = std::find_if(m_mapIndexToFileGuid.begin(),
m_mapIndexToFileGuid.end(), map_value_finder(task->pFileInfo->fileID));创建一个map_value_finder的临时对象,直接调用其对象的operator()即可。
如果想要定义模板类型的多类型参数接收的代码,个人愚见如下:
#include <map>
#include <utility>
template<class Key, class Value>
class TzStdMapValueFinder
{
public:
TzStdMapValueFinder(Key & key, Value & value) : m_key(key), m_value(value)
{
}
bool operator() (const typename std::map<Key, Value>::value_type & sPair)
{
if (sPair.second == m_value)
{
return true;
}
return false;
}
private:
const Key & m_key;
const typename Value& m_value;
};上述类在使用的时候类似下面的情况:
void testMap(void)
{
std::map<int, QString> mapT;
for (int i = 0; i < 10; i++)
{
mapT[i] = "Number : " + QString::number(i);
}
std::map<int, QString>::iterator iter = mapT.end();
QString str("Number : 1");
int num = 0;
TzStdMapValueFinder<int, QString> p(str, num);
iter = std::find_if(mapT.begin(), mapT.end(), p);
qDebug() << __FILE__ << __LINE__ << __FUNCDNAME__ << iter->first << iter->second;
}单独函数专门处理
或者, 单独一个函数,此函数专门用来查找value_type, 具体情况如下:
QString strGlobal = "D";
bool TestFindValue(const std::map<int,QString>::value_type &pair)
{
if(pair.second.compare(strGlobal) == 0)
return true;
return false;
}调用的时候:
std::map<int, QString>::iterator iter = std::find_if(map_Test.begin(), map_Test.end(), TestFindValue);直接传入函数地址即可。这种用法就比较繁琐,使用时需要自己去存储value。
个人倾向于第一种,网上很多资源也是提供的第一种。另外:std::map 插入的2种方式比较:
- insert: map.insert(std::makepair(key,value));
- map[key]=value;
区别:
1. 第一种方式,遍历map,如果没找到key,则插入,否则不插入。
2. 第二种方式,如果没找到则插入,否则将对应的key项的值赋给value。
你可能觉得,第二种方式多好,找不到就插入,比第一种靠谱多了。第二种方式确实更靠谱,但是比起第一种方式,它的代价会更大,这种靠谱是要花时间的。
尤其在遇到value为对象的情况时,就需要好好考虑了。
因为第二种方式相当于是:系统先默认构造一个对象,然后给它赋值,最后还要销毁它(3部分时间)。如果用想要的value赋给对象,显然比默认构造一个对象再赋值更高效。这就是insert。
当对象内属性很多时就更应该考虑了。
具体insert的返回值,可以再深入了解下,比如插入是否成功。
返回值为一个pair,pair构成一个迭代器,一个bool变量,bool变量标识是否插入成功,iterator指向插入成功的map元素。
mymap.insert ( std::pair<char,int>('a',100) );
mymap.insert ( std::pair<char,int>('z',200) );
std::pair<std::map<char,int>::iterator,bool> ret;
ret = mymap.insert ( std::pair<char,int>('z',500) );
if (ret.second==false) {
std::cout << "element 'z' already existed";
std::cout << " with a value of " << ret.first->second << '\n';
}
















