如果你想要把一个容器内的所有元素累加起来,应该怎么办?
STL 的 accumulate 可以让我们不必自己写循环:
#include <iostream>#include <functional>#include <numeric>#include <vector>#include <string>int main(){ std::vector<int> vect; vect.push_back(1); vect.push_back(2); vect.push_back(3); vect.push_back(4); std::cout << "Accumulate: " << std::accumulate( vect.begin(), vect.end(), 0, std::plus<int>());}输出:
Accumulate: 10其中的 std::plus<int>() 可以省略,因为这将是3个参数的 accumulate 的默认行为。 注意 accumulate 算法是定义在 numeric 里面而不是 algorithm 里面的。
由于 accumulate 和 plus 都是泛型的,所以如果你要累加的不是 int 而是字符串,对程序的修改也并不大:
#include <iostream>#include <functional>#include <numeric>#include <vector>#include <string>int main(){ std::vector<std::string> vect; vect.push_back("1"); vect.push_back("2"); vect.push_back("3"); vect.push_back("4"); std::cout << "Accumulate: " << std::accumulate( vect.begin(), vect.end(), std::string(""));}输出:
Accumulate: 1234不过,如果使用 boost.lambda ,这个问题会有一些很好看又容易理解的解法:
#include <iostream>#include <algorithm>#include <numeric>#include <vector>#include <string>#include <boost/lambda/lambda.hpp>#include <boost/lambda/bind.hpp>//#include <boost/bind.hpp>using namespace boost::lambda;//using namespace boost;int main(){ std::vector<std::string> vect; vect.push_back("1"); vect.push_back("2"); vect.push_back("3"); vect.push_back("4"); std::string result; std::for_each( vect.begin(), vect.end(), result += _1); std::cout << result;}输出:
1234这里要借用变量 result ,在这个程序中显得多了几行,但是我们调用 accumulate 的目的也往往是把结果放到一个变量中,这样的话,使用 boost.lambda 反而会漂亮一些。
在上面的程序中,另一个丑陋的地方就是 vector 的初始化,为了把 1, 2, 3, 4 放进 vect 里面,我们居然要调用 push_back 4次!不过,使用 boost.lambda 就好得多了。
std::vector<int> vect(10); int i = 0; std::for_each( vect.begin(), vect.end(), _1 = ++var(i) );这里有两个地方值得注意:
1. 现在必须在 vect 的声明中指出其大小,否则 for_each 对一个空容器可是什么也不会做
2. 必须使用 ++var(i) ,而不是 ++i 。var 在这里的作用是强迫 lazy evaluation ,也就是让变量在被用到的时候在求值,如果用 ++i ,你会得到一个装有10个1的 vect ,而不是装有1-10。
=================================================================================
许多问题遇到 map 都会变得复杂起来,如果想要把一个 map 中所有的 key 或者 value 累加起来,该怎么办呢?这个时候已经不能直接使用 accumulate 了,用 boost.bind 可以办到,做法是这样的:
#include <iostream>#include <algorithm>#include <numeric>#include <map>#include <string>#include <boost/bind.hpp>using namespace boost;int main(){ std::map<int, std::string> persons; persons[123] = "Amy"; persons[234] = "Ralph"; persons[345] = "Simon"; persons[456] = "Maggie"; std::cout << std::accumulate( persons.begin(), persons.end(), 0, bind(std::plus<int>(), _1, bind(&std::map<int, std::string>::value_type::first, _2)) ) << std::endl; std::cout << std::accumulate( persons.begin(), persons.end(), std::string(), bind(std::plus<std::string>(), _1, bind(&std::map<int, std::string>::value_type::second, _2)) ) << std::endl;}输出:
1158AmyRalphSimonMaggie办是办到了,但是平心而论,的确算不上是漂亮。连续的 bind 并不比自己写的循环更让人头晕。boost.lambda 也要用到 bind ,然而可以清晰许多:
#include <iostream>#include <algorithm>#include <numeric>#include <map>#include <string>#include <boost/lambda/lambda.hpp>#include <boost/lambda/bind.hpp>using namespace boost::lambda;int main(){ std::map<int, std::string> persons; persons[123] = "Amy"; persons[234] = "Ralph"; persons[345] = "Simon"; persons[456] = "Maggie"; int iresult = 0; std::string sresult; std::for_each( persons.begin(), persons.end(), iresult += bind(&std::map<int, std::string>::value_type::first, _1) ); std::for_each( persons.begin(), persons.end(), sresult += bind(&std::map<int, std::string>::value_type::second, _1) ); std::cout << iresult << std::endl; std::cout << sresult << std::endl;}输出和上面的一样:
1158AmyRalphSimonMaggie有了它的帮助,即便间接层次再增加一层,也不会有太多困难:假如你的 map 并不直接存储 string ,而是存储 Person 对象,而它们的名字要通过 Name() 方法来取得,代码只需要稍微的修改:
#include <iostream>
#include <algorithm>
#include <numeric>
#include <map>
#include <string>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
using namespace boost::lambda;
class Person
{
public:
Person(){}
Person(const std::string& name) : name_(name){}
std::string& Name()
{ return name_; }
private:
std::string name_;
};
int main()
{
std::map<int, Person> persons;
persons[123] = Person("Amy");
persons[234] = Person("Ralph");
persons[345] = Person("Simon");
persons[456] = Person("Maggie");
std::string result;
std::for_each( persons.begin(), persons.end(),
result += bind(&Person::Name, bind(&std::map<int, Person>::value_type::second, _1))
);
std::cout << result;
}
输出:
AmyRalphSimonMaggie
分享到:
相关推荐
Java 第二阶段提升编程能力【泛型】---- 代码 Java 第二阶段提升编程能力【泛型】---- 代码 Java 第二阶段提升编程能力【泛型】---- 代码 Java 第二阶段提升编程能力【泛型】---- 代码 Java 第二阶段提升编程能力...
补充知识:泛型1---马克-to-win java视频的详细描述与介绍
补充知识2 ---马克-to-win java视频泛型的详细描述与介绍
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...
C++泛型编程:源起、实现与意义,免积分下载。
NULL 博文链接:https://simon-9527.iteye.com/blog/2307148
From Mathematics to Generic Programming 数学与泛型编程:高效编程的奥秘 英文版
因为这部分操作可以抽象出来为所有的容器工作,那就是泛型算法。所谓“泛型”是指这些算法可以应用于多种容器类型上,而容器内的元素类型也可以多样化。标准库提供了100多个泛型算法,主要定义于头文件中,还有一组...
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是...
第一分钟:委托 第二分钟:匿名方法 第三分钟:Lambda表达式 第四分钟:泛型委托 第五分钟:表达式树
泛型由入门到精通
Object-C的教程可以从基础语法、面向对象编程、集合与泛型、实践项目等多个方面入手。以下是一个简要的Object-C教程框架,帮助你了解学习Object-C所需的基本步骤和内容: 一、Object-C基础语法 变量与数据类型:...
数学和泛型编程-高效编程的奥秘(英文版pdf)原名:From_Mathematics_to_Generic_Programming,作者;Alexander A. Stepanov Daniel E. Rose
泛型算法.CHM(已经编译的帮助文档),对C++很有帮助,文档小,方便
GP-泛型算法通用原则
这些是关于c++ primer的练习题和 测试题 ,自己感觉还不错 大家可以看看
C++Primer第11章-泛型算法-课后习题答案[收集].pdf
2:有关Switch的一些知识 3:服务器与客户端通信: 4:java.util.Date与java.sql.Date的运用 5:泛型学习 6:SQL预编译 7:i++和++i的区别 8:判断输入文本是否全是半角空格js 9:java中金额的精确计算问题 10:有关...