Effective STL学习笔记-条款37

来源:互联网 发布:caffe softmax 参数 编辑:程序博客网 时间:2024/06/03 18:04

用accumulate或for_each来统计区间

一般的统计算法可以使用count和count_if来替代,他们告诉你某个区间有多少等于某个值的元素。
而accumulate和for_each是对于区间的的统计。

accumulate

看个简单例子:

    list<double> ld = { 0.0, 0.1, 1.1, 2.2, 3.0 };    double sum = std::accumulate(ld.begin(), ld.end(), 1.1);    cout << "sum :" << sum << endl;

这个结果就是sum:7.5,他是从第一个元素1.1开始逐步累加区间的数值

我们还可以按照自己的想法给定一个仿函数实现各种累加:

string::size_type stringLenSum(string::size_type sum, const string& s){    return sum + s.size();}    set<string> ss = { "a", "abc" };    string::size_type ssum = accumulate(ss.begin(),        ss.end(), 0, stringLenSum);    cout << "ssum:" << ssum << endl;

打印结果为4。

让他计算区间的积将更简单,因为我们可以使用标准的multiplies仿函数类:

    vector<float> vf = { 1.0f, 1.2f, 2.0f };    float product = accumulate(vf.begin(), vf.end(),        1.0f, multiplies<float>());    cout << "vf : " << product << endl;

计算结果为:2.4f。特别注意计算乘积起始值如果为0,那么结果都是0了。

最后一个晦涩点的例子,他用来寻找point区间的平均值,并且我们也可以看一下accumulate和for_each的区别。

struct Point{    Point(double x_, double y_) :x(x_), y(y_) {};    double x;    double y;};//增加一个处理的仿函数,我们可以按照以下方式使用    vector<Point> lp =    {        { Point(1.0, 2.0) },        { Point(2.0, 4.0) },        { Point(3.0, 6.0)},    };    Point avg = std::accumulate(lp.begin(), lp.end(), Point(0,0), PointAvg());    cout << "Point:" << avg.x << "  " << avg.y << endl;

接下来是使用accumulate方式的仿函数实现:

class PointAvg{public:    PointAvg():nums(0),xSum(0.0),ySum(0.0){}    const Point operator()(const Point& avg, const Point& p)    {        ++nums;        xSum += p.x;        ySum += p.y;        return Point(xSum / nums, ySum / nums);    }private:    size_t nums;    double xSum;    double ySum;};

然而实际上,成员变量的nums,xSum和ySum的存在,可能会造成副作用,技术上讲,以上代码会导致结果未定义。所以for_each出场了。

  • 除了副作用问题,for_each和accumulate的不同主要在两个方面。首先,accumulate的名字表示它是一个产生区
    间统计的算法,for_each听起来好像你只是要对区间的每个元素进行一些操作,而且,当然,那是那个算法
    的主要应用。用for_each来统计一个区间是合法的,但是它没有accumulate清楚。
  • 其次,accumulate直接返回那些我们想要的统计值,而for_each返回一个函数对象,我们必须从这个对象中提取想要的统计信息。在C++里,那意味着我们必须给仿函数类添加一个成员函数,让我们找回我们追求的统计信息。
class PointAvg{public:    PointAvg():nums(0),xSum(0.0),ySum(0.0){}    void operator()(const Point& p)    {        ++nums;        xSum += p.x;        ySum += p.y;    }    Point result() const    {        return Point(xSum / nums, ySum / nums);    }private:    size_t nums;    double xSum;    double ySum;};    Point avg2 = std::for_each(lp.begin(), lp.end(), PointAvg()).result();    cout << "Point:" << avg2.x << "  " << avg2.y << endl;

就个人来说,我更喜欢用accumulate来统计,因为我认为它最清楚地表达了正在做什么,但是for_each也可
以,而且不像accumulate,副作用的问题并不跟随for_each。两个算法都能用来统计区间。使用最适合你的那
个。
你可能想知道为什么for_each的函数参数允许有副作用,而accumulate不允许。这是一个刺向STL心脏的探针
问题。唉,尊敬的读者,有一些秘密总是在我们的知识范围之外。为什么accumulate和for_each之间有差别?
我尚待听到一个令人信服的解释。 — 原作者。

原创粉丝点击