如果你想要把一個(gè)容器內(nèi)的所有元素累加起來(lái),應(yīng)該怎么辦?
如果你想要把一個(gè)容器內(nèi)的所有元素累加起來(lái),應(yīng)該怎么辦?
STL 的 accumulate 可以讓我們不必自己寫循環(huán):
#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>() 可以省略,因?yàn)檫@將是3個(gè)參數(shù)的 accumulate 的默認(rèn)行為。 注意 accumulate 算法是定義在 numeric 里面而不是 algorithm 里面的。
由于 accumulate 和 plus 都是泛型的,所以如果你要累加的不是 int 而是字符串,對(duì)程序的修改也并不大:
#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
不過(guò),如果使用 boost.lambda ,這個(gè)問(wèn)題會(huì)有一些很好看又容易理解的解法:
#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 ,在這個(gè)程序中顯得多了幾行,但是我們調(diào)用 accumulate 的目的也往往是把結(jié)果放到一個(gè)變量中,這樣的話,使用 boost.lambda 反而會(huì)漂亮一些。
在上面的程序中,另一個(gè)丑陋的地方就是 vector 的初始化,為了把 1, 2, 3, 4 放進(jìn) vect 里面,我們居然要調(diào)用 push_back 4次!不過(guò),使用 boost.lambda 就好得多了。
? std::vector<int> vect(10);
? int i = 0;
? std::for_each( vect.begin(), vect.end(), _1 = ++var(i) );
這里有兩個(gè)地方值得注意:
1. 現(xiàn)在必須在 vect 的聲明中指出其大小,否則 for_each 對(duì)一個(gè)空容器可是什么也不會(huì)做
2. 必須使用 ++var(i) ,而不是 ++i 。var 在這里的作用是強(qiáng)迫 lazy evaluation ,也就是讓變量在被用到的時(shí)候在求值,如果用 ++i ,你會(huì)得到一個(gè)裝有10個(gè)1的 vect ,而不是裝有1-10。
=================================================================================
許多問(wèn)題遇到 map 都會(huì)變得復(fù)雜起來(lái),如果想要把一個(gè) map 中所有的 key 或者 value 累加起來(lái),該怎么辦呢?這個(gè)時(shí)候已經(jīng)不能直接使用 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;
}
輸出:
1158
AmyRalphSimonMaggie
辦是辦到了,但是平心而論,的確算不上是漂亮。連續(xù)的 bind 并不比自己寫的循環(huán)更讓人頭暈。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;
}
輸出和上面的一樣:
1158
AmyRalphSimonMaggie
有了它的幫助,即便間接層次再增加一層,也不會(huì)有太多困難:假如你的 map 并不直接存儲(chǔ) string ,而是存儲(chǔ) Person 對(duì)象,而它們的名字要通過(guò) Name() 方法來(lái)取得,代碼只需要稍微的修改:
#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