最近因为一直在面试,所以一直在准备,现在工作总算是有点着落了,所以就继续开始我的学习之旅。今天我们来总结STL容器中的std::find,std::find_if以及LAMABDA表达式的用法。为什么会突然写这个呢?这是因为最近笔者最近碰到一个技术问题,就是我有一些长的字符串(20位以上)(存放到list中的元素类中的某个成员变量中),然后呢,因为某些原因,底层上报上来的字符串有重复,那么我们现在需要把它过滤掉,有什么好办法呢?首先用memcmp这种方法是不可能的,算法效率太低了。能想到的有这几种。
一、可以采用set容器把这些东西全部导入进去,然后在把它导出来就好了。但是这样做有个缺点,就是因为我后面都用这个list读取数据,如果都改会比较麻烦,所以我果断放弃了。
二、可以采用hash校验的方法,这个方法需要添加算法不说,最终要的是我这边生成的hash校验和字符串校验差不多长度,压根也没这必要。
三、采用STL容器中的find和find_if的用法来进行处理,我果断选择了第三种。
好,接下来我们开始研究一下这些内容。
一、STL容器中find的用法
二、STL容器中find_if的用法
三、LAMBDA表达式到底是个啥?
四、为什么要用LABMBDA表达式
一、STL容器中find的用法
首先说一下,STL容器中有很多find,比如说set,map。他们内部都有内置的find函数,一般情况下,如果我们用到这些容器,那么我们直接用它的内置find就可以了。(这是因为map和set中内置的find函数比std::find时间复杂度要低,速度更快)。但是像list,vector这些容器是没有find函数的,所以我们只能用默认的std::find来进行查找。首先说一下find函数的原型
template<class InputIterator, class T>
InputIterator find ( InputIterator first, InputIterator last, const T& value )
{
for ( ;first!=last; first++)
if ( *first==value ) break;
return first;
}
我们从find的定义中可以看到,find内部一共包含三个参数,第一个参数和第二个参数指的是迭代器的头部和尾端,而第三个参数表示的是要比较的值。(不过这里要注意这个值必须是const类型的,所以我们在后面的赋值过程中也要赋值成const类型)。
废话不说,看一个最简单的例子。
std::vector<int> score{ 10, 20, 30, 40 }; // 待查找
key int find_key_10 = 10; // 找一个存在于数组中的元素
auto ret_val_1 = std::find(score.begin(), score.end(), find_key_10);
if (score.end() != ret_val_1)
std::cout << "找到了 10 了 ";
else
std::cout << "没有找到 10 "; // 找一个不在数组中的元素
int find_key_50 = 50;
auto ret_val_2 = std::find(score.begin(), score.end(), find_key_50);
if (score.end() != ret_val_2)
std::cout << "找到了 50 了 ";
else
std::cout << "没有找到 50 ";
只看标红的这一句,这就是find的一个最简单的用法,第一个参数和第二个参数分别传递STL容器的头端和尾端,而第三个参数我们直接传入一个常量,然后直接进行判断,如果说没有找到,那么它返回的值一定是到尾端,反之返回的就是中间的迭代器。
但是这里有个问题,那就是如果说我们传入的vector或者list容器不是一个基本类型呢?比如说这样:
class CPerson
{
public:
CPerson(void);
~CPerson(void);
int getage(){return age;
}
private:
int age; // 年龄
};
我们这里要比较其中的age是否相等,那么我们仿照上面的例子应该怎么书写呢
std::vector<Cperson> score;
// 插入数据
CPerson c;
c.age = 20;
auto ret_val_2 = std::find(score.begin(), score.end(), c);
// 比较
好的,那么我们根据find的定义来分析一下这个find语句,根据find定义,我们执行过程会是这样
for ( ;first!=last; first++)
if ( *first==c ) break;
return first;
这样就变成了类进行比较,不用说,编译肯定是报错的。而且也没有按照我们的age来解决。
那么我们该怎么解决这个问题呢?其实问题的关键就在于first==c这句话上,所以我们最容易的解决方案就是重载==运算符。我们可以在类中添加这样的话。
class CPerson
{
public:
CPerson(void);
~CPerson(void);
int getage(){return age;
}
bool CPerson::operator==(const CPerson &rhs) const
{
return (age == rhs.age);
}
private:
int age; // 年龄
};
这样问题就解决了。
但是这样设置的条件有点窄,比如说我如果要求找到的这个值自动在类中加30怎么办呢?这就需要find_if函数了。
我们首先来看一下find_if的用法
template<class InputIterator, class Predicate>
InputIterator find_if(InputIterator _First, InputIterator _Last, Predicate _Pred);
我们从find_if定义上可知,find_if上也有三个参数,其中前两个参数是和find代表是相同的,但是第三个参数是我们自定义的函数。
直接上例子:
class CPerson
{
public:
CPerson(void);
~CPerson(void);
int getage(){return age;
}
bool CPerson::operator() (const CPerson &rhs) const
{
if (age == rhs.age) {
rhs.age +=30;
return true;
}
}
private:
int age; // 年龄
};
std::vector<Cperson> score;
// 插入数据
CPerson c;
c.age = 20;
auto ret_val_2 = std::find_if(score.begin(), score.end(), c);
这里的区别在于之前是重载了==,现在是重载了(),换句话说,这里的空间要大一些。
三、LAMBMA表达式
当然,作为一个懒人其实还有一种方法,那就是把LAMBDA表达式融入到其中,我们可以这样写:
int age = 30;
auto ret_val_2 = std::find_if(score.begin(), score.end(), [age](const Cperson &rhs))-> bool {
return age == rhs.getage();
}
这里要说的一点就是getage返回必须是个常量,因为find_if就是这么定义的。
四、说一下为什么要用LAMBMA表达式
使用LAMBDA表达式有两个原因,第一个原因在于LAMBDA表达式时在函数中间定义,这样比较好查找。
第二个原因在于LAMBDA表达式使用起来比较方便,可以直接操纵动态参数,如果不然我们还得重新写一个构造函数,把参数传进去进行比较,多有不便,综上所述,所以一般我都用LAMBDA表达式来写。
今天就分享到这里了