泛型算法:Tips (2) --- 累加

来源:互联网 发布:软件用户使用说明书 编辑:程序博客网 时间:2024/05/17 14:28
如果你想要把一个容器内的所有元素累加起来,应该怎么办?

STL 的 accumulate 可以让我们不必自己写循环:

#include
#include
#include
#include
#include

int main()
{
  std::vector 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());
}

输出:

Accumulate: 10

其中的 std::plus() 可以省略,因为这将是3个参数的 accumulate 的默认行为。 注意 accumulate 算法是定义在 numeric 里面而不是 algorithm 里面的。

由于 accumulate 和 plus 都是泛型的,所以如果你要累加的不是 int 而是字符串,对程序的修改也并不大:

#include
#include
#include
#include
#include

int main()
{
  std::vector 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
#include
#include
#include
#include

#include
#include
//#include

using namespace boost::lambda;
//using namespace boost;

int main()
{
  std::vector 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 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
#include
#include
#include
#include

#include

using namespace boost;

int main()
{
  std::map 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(), _1, bind(&std::map::value_type::first, _2)) )
    << std::endl;

  std::cout << std::accumulate( persons.begin(), persons.end(), std::string(),
    bind(std::plus(), _1, bind(&std::map::value_type::second, _2)) )
    << std::endl;
}

输出:

1158
AmyRalphSimonMaggie

办是办到了,但是平心而论,的确算不上是漂亮。连续的 bind 并不比自己写的循环更让人头晕。boost.lambda 也要用到 bind ,然而可以清晰许多:

#include
#include
#include
#include
#include

#include
#include

using namespace boost::lambda;

int main()
{
  std::map 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::value_type::first, _1)
  );
 
  std::for_each( persons.begin(), persons.end(),
    sresult += bind(&std::map::value_type::second, _1)
  );
 
  std::cout << iresult << std::endl;
  std::cout << sresult << std::endl;
}

输出和上面的一样:

1158
AmyRalphSimonMaggie

有了它的帮助,即便间接层次再增加一层,也不会有太多困难:假如你的 map 并不直接存储 string ,而是存储 Person 对象,而它们的名字要通过 Name() 方法来取得,代码只需要稍微的修改:

#include
#include
#include
#include
#include

#include
#include

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 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::value_type::second, _1))
  );
 
  std::cout << result;
}

输出:

AmyRalphSimonMaggie





原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 轻伤过了追诉期怎么办 判决生效书丢了怎么办 高层17楼水压低怎么办 高层六楼水压低怎么办 高层6楼水压低怎么办 高层5楼水压低怎么办 高层五楼水压小怎么办 高层四楼水压低怎么办 高层6楼水压不够怎么办 马桶水箱盖坏了怎么办 马桶水箱盖子坏了怎么办 绿萝的叶子黄了怎么办 绿萝叶子烂了怎么办 还款协议签订后一方反悔怎么办 签了协议想反悔怎么办 体温计打碎了水银找不到了怎么办 模拟城市5核电站爆炸怎么办 日本地铁票丢了怎么办 在日本地铁票丢了怎么办 首付交了没合同怎么办 工程干完不给签合同怎么办 寄存密码纸丢了怎么办 超市柜子纸丢了怎么办 楼下有污水井味道怎么办 孕妇闻到了烧垃圾怎么办 楼下9米垃圾房怎么办 在工厂上班得了职业病怎么办 自来水被农药水污染了怎么办 雾霾天头疼恶心怎么办? 夫妻住宾馆一个没有身份证怎么办 医保报销后认定工伤怎么办 结肠癌术后复查有息肉怎么办 无蒂息肉恶变要怎么办 贤者时间很长怎么办 鸡吃了酒米醉了怎么办 自填脂肪乳房脂肪液化怎么办 中国人在外国遇到危险怎么办 dnf刷图卡住了怎么办 dbf深渊怪卡住了怎么办 dnf86级没任务了怎么办 dnf二觉任务没了怎么办