C++ Coding Reference: std::accumulate() and examples
- 时间:2020-09-17 14:37:27
- 分类:网络文摘
- 阅读:74 次
The Reduce in terms of Map-Reduce is often referring to reducing many values (vector) to a single value (scalar). In C++, the STL has a accumulate() method that allows you to reduce a vector/list to a single value by providing the initial value, and the reducer function.
The std::accumulate() is provided in C++ header numeric and it has the following template definition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // FUNCTION TEMPLATE accumulate template<class _InIt, class _Ty, class _Fn> _NODISCARD inline _Ty accumulate(const _InIt _First, const _InIt _Last, _Ty _Val, _Fn _Reduce_op) { // return noncommutative and nonassociative reduction of _Val and all in [_First, _Last), using _Reduce_op _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); for (; _UFirst != _ULast; ++_UFirst) { _Val = _Reduce_op(_Val, *_UFirst); } return (_Val); } |
// FUNCTION TEMPLATE accumulate template<class _InIt, class _Ty, class _Fn> _NODISCARD inline _Ty accumulate(const _InIt _First, const _InIt _Last, _Ty _Val, _Fn _Reduce_op) { // return noncommutative and nonassociative reduction of _Val and all in [_First, _Last), using _Reduce_op _Adl_verify_range(_First, _Last); auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); for (; _UFirst != _ULast; ++_UFirst) { _Val = _Reduce_op(_Val, *_UFirst); } return (_Val); }
By default, if the reduce op (or Reducer function) is not specified, the accumulator will use a plus operator. For example,
1 2 | vector<int> nums({1, 2, 3, 4, 5}); cout << std::accumulate(begin(nums), end(nums), 0); // output 15, which is 1+2+3+4+5 |
vector<int> nums({1, 2, 3, 4, 5}); cout << std::accumulate(begin(nums), end(nums), 0); // output 15, which is 1+2+3+4+5
The first and second parameter specifies the range of the vector, which you can pass begin() and end() iterators of a C++ vector for example. The third parameter of the accumulate() is the initial value that will be accumulated from.
Default reducer can be expressed explicitly by the lambda function, for example,
1 2 3 4 | vector<int> nums({1, 2, 3, 4, 5}); cout << std::accumulate(begin(nums), end(nums), 0, [](auto &a, auto &b) { return a + b; }); // output 15, which is 1+2+3+4+5 |
vector<int> nums({1, 2, 3, 4, 5}); cout << std::accumulate(begin(nums), end(nums), 0, [](auto &a, auto &b) { return a + b; }); // output 15, which is 1+2+3+4+5
We can also use other pre-defined reducer, for example, std::multiplies which is defined in header xstddef.
1 2 3 4 5 6 7 8 9 10 11 12 13 | // STRUCT TEMPLATE multiplies template<class _Ty = void> struct multiplies { // functor for operator* _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty result_type; constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const { // apply operator* to operands return (_Left * _Right); } }; |
// STRUCT TEMPLATE multiplies template<class _Ty = void> struct multiplies { // functor for operator* _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty first_argument_type; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty second_argument_type; _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef _Ty result_type; constexpr _Ty operator()(const _Ty& _Left, const _Ty& _Right) const { // apply operator* to operands return (_Left * _Right); } };
An example for the integer factorial e.g. 5! = 5x4x3x2x1 = 120. Remember to set the initial reducer value to 1 instead of 0.
1 2 3 | vector<int> nums({1, 2, 3, 4, 5}); // output 120, which is 1*2*3*4*5 cout << std::accumulate(begin(nums), end(nums), 1, std::multiplies<int>()); |
vector<int> nums({1, 2, 3, 4, 5}); // output 120, which is 1*2*3*4*5 cout << std::accumulate(begin(nums), end(nums), 1, std::multiplies<int>());
C++ accumulate() the string
We can use accumulate() to apply to strings, however, the initial value has to be string explicitly. By default, empty string with double quotes in C++ is treated as const char * which is not desired.
1 2 3 | string s = "Hello"; string ss = std::accumulate(begin(s), end(s), string("")); std::cout << ss.c_str(); // Hello |
string s = "Hello"; string ss = std::accumulate(begin(s), end(s), string("")); std::cout << ss.c_str(); // Hello
The string(“”) can also be expressed as string{}. Another example with the lambda reducer function.
1 2 3 4 5 | string s = "Hello"; string ss = std::accumulate(begin(s), end(s), string{}, [](auto &a, auto &b) { return a + b + ","; }); std::cout << ss.c_str(); // H,e,l,l,o, |
string s = "Hello"; string ss = std::accumulate(begin(s), end(s), string{}, [](auto &a, auto &b) { return a + b + ","; }); std::cout << ss.c_str(); // H,e,l,l,o,
We are using the auto to let the compiler deduce the type, but if you want to explicitly specify the type in the reducer function, that is OK:
1 2 3 | string ss = std::accumulate(begin(s), end(s), string{}, [](const string &a, const char &b) { return a + b + ","; }); |
string ss = std::accumulate(begin(s), end(s), string{}, [](const string &a, const char &b) { return a + b + ","; });
The C++ std::accumulate performs a left-fold meaning that the values in the vector are reduced from left to right. To reduce in right-fold i.e. from right to left, you can either reverse the argument vector, or pass the reverse iterators.
–EOF (The Ultimate Computing & Technology Blog) —
推荐阅读:数学题:甲乙丙三人的平均年龄为22岁 数学题:在一块边长60m的正方形花坛四边种冬青树 数学题:用一根铁丝刚好焊成一个棱长10厘米的正方体框架 数学题:一艘船在静水中每小时行驶40千米 数学题:在AB两点之间等距离安装路灯 数学题:一种商品随季节出售 数学题:一个底面半径是6厘米的圆柱形玻璃器皿里装有一部分水 数学题:已知点D、E、F分别是BC、AD、BE上的中点 数学题:21个同学来取水果 数学题:四一班买了30只红气球和黄气球装点教室
- 评论列表
-
- 添加评论