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:
// 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,
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,
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.
// 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.
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.
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.
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:
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.
C/C++ Programming
- Understanding std::transform_reduce in Modern C++
- Implement a Lock Acquire and Release in C++
- Detecting Compile-time vs Runtime in C++: if consteval vs std::is_constant_evaluated()
- C++ Forward References: The Key to Perfect Forwarding
- Understanding dynamic_cast in C++: Safe Downcasting Explained
- C vs C++: Understanding the restrict Keyword and its Role in Optimization
- C++ Lvalue, Rvalue and Rvalue References
- C++ assert vs static_assert
- Why auto_ptr is Deprecated in C++?
- C++ What is the consteval? How is it different to const and constexpr?
- Tutorial on C++ std::move (Transfer Ownership)
- const vs constexpr in C++
- Tutorial on C++ Ranges
- Tutorial on C++ Smart Pointers
- Tutorial on C++ Future, Async and Promise
- The Memory Manager in C/C++: Heap vs Stack
- The String Memory Comparision Function memcmp() in C/C++
- Modern C++ Language Features
- Comparisions of push_back() and emplace_back() in C++ std::vector
- C++ Coding Reference: is_sorted_until() and is_sorted()
- C++ Coding Reference: iota() Setting Incrementing Values to Arrays or Vectors
- C++ Coding Reference: next_permutation() and prev_permutation()
- C++ Coding Reference: count() and count_if()
- C++ Code Reference: std::accumulate() and Examples
- C++ Coding Reference: sort() and stable_sort()
- The Next Permutation Algorithm in C++ std::next_permutation()
–EOF (The Ultimate Computing & Technology Blog) —
698 wordsLast Post: C++ Coding Reference: sort() and stable_sort()
Next Post: How to Reorder Data in Log Files using the Custom Sorting Algorithm?