- rule37:用accumulate或for_each来做区间统计
count函数能够告诉你区间有多少个等于某个值的元素,而count_if告诉你有多少个元素满足一个判断式。区间的最大值和最小值可以通过min_element和max_element获得。
有时,你需要自己定义对区间的统计信息,比如求和一个区间的元素和,对一个容器中的字符串长度求和。
accumulate函数存在于numeric中。accumulate存在两种形式。
如下:
list<double> ld;
ld.push_back(20);
ld.push_back(1.1);
double sum = accumulate(ld.begin(),ld.end(),0.0);
注意初始值指定为0.0,这很重要。0.0的类型是double,所以accumulate内部使用了一个double类型的变量来存储计算的和。写成0的话就会发生强制转换,导致失掉精度。
accumulate还有一种形式,它带有一个初始值和一个任意的统计函数,使用方法如下:
string::size_type stringLenthSum(string::size_type sumSoFar,const string& s)
{
return sumSoFar+s.size();
}
//测试代码
set<string> ss;
ss.insert("123456789");
ss.insert("abc");
ss.insert("def");
string::size_type length = accumulate(ss.begin(),ss.end(),0,stringLenthSum);
size_type 的类型其实和size_t一样。也可以与int直接转换。length 的结果为15。
计算数值区间的积更简单,我们不用写自己的乘积函数,我们可以使用标准的multiplies仿函数类:
vector<float> vf;
float product = accumulate(vf.begin(),vf.end(),1.0,multiplies<float>());
下面我贴一段使用仿函数类的代码,实现计算一个区间的点集合的平均值,这一算法,仿函数在以后会提到。我们先有一个直观的感受。
struct Point
{
double x;
double y;
Point(double x,double y)
{
this->x = x;
this->y = y;
}
};
class PointAverage:public unary_function<Point,void>{
private:
size_t numPoints;
double xSum;
double ySum;
public:
PointAverage():xSum(0),ySum(0),numPoints(0){}
void operator()(const Point&p)
{
++numPoints;
xSum+=p.x;
ySum+=p.y;
}
Point result() const{
return Point(xSum/numPoints,ySum/numPoints);
}
};
//调用函数
list<Point> Ip;
Ip.push_back(Point(1,2));
Ip.push_back(Point(5,2));
Point avg = for_each(Ip.begin(), Ip.end(), PointAverage()).result();
这就是仿函数类的作用。for_each返回一个函数对象,我们可以从这个对象中提取想要的统计信息。在C++中,也就意味着我们必须给仿函数类添加一个成员函数。