Effective STL学习笔记-条款37

8 篇文章 0 订阅

用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之间有差别?
我尚待听到一个令人信服的解释。 — 原作者。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
侯捷的《STL源码剖析》是一本关于STL(标准模板库)的学习笔记。这本书深入解析了STL的实现原理和设计思路,对于理解STL的内部机制和使用方法非常有帮助。这些学习笔记记录了作者在学习侯捷的《STL标准库和泛型编程》课程时的心得和总结,对于理解STL源码和进行泛型编程都具有指导意义。 这本书涉及了STL的各个模块,包括容器、迭代器、算法等,并解释了它们的实现原理和使用方法。通过学习这本书,你可以更好地理解STL的底层实现和使用技巧。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [STLSourceAnalysis:stl原始码剖析(侯捷)的学习笔记](https://download.csdn.net/download/weixin_42175776/16069622)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [候捷老师STL源码剖析视频课程笔记](https://blog.csdn.net/weixin_46065476/article/details/125547869)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [侯捷——STL源码剖析 笔记](https://blog.csdn.net/weixin_45067603/article/details/122770539)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值