[c + +] for in c + +_ Each and accumulate functions

Keywords: Algo

for_each function

for_each function is defined in the < algorithm > header file, and its function declaration is:

template<class InputIt, class UnaryFunction>
constexpr UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f)
{
    for (; first != last; ++first) {
        f(*first);
    }
    return f; // implicit move since C++11
}

Receive two iterators, first and last, traverse the elements within the range of [first, last], pass them to the function or function object F, and return the function or function object f after traversal

f can be a function, a function object, or a lambda expression

Using functions as predicates

void print(const int &a) {
    cout << a << " ";
}

int main() {
    std::vector<int> nums{3, 4, 2, 8, 15, 267};
    // After traversing the for_each function, the predicate will be returned
    void (*pfunc)(const int &) = for_each(nums.begin(), nums.end(), print);
    cout << endl;
    pfunc(6);
}

Using function objects as predicates

As long as it is a class or structure that overloads the () operator, it is a function object class, and the instance of this class is a function object.

The member attribute and member method in the structure are public by default

The member properties and methods in the class are private by default

struct Sum {
    Sum() : sum{0} {}

    // Overload () operator
    void operator()(int n) { sum += n; }

    int sum;
};


std::vector<int> nums{3, 4, 2, 8, 15, 267};
//Pass the element traversal in the container to the function object respectively for accumulation, and return the function object after traversal
Sum s = std::for_each(nums.begin(), nums.end(), Sum());
//Get accumulation result from function object
std::cout << "sum: " << s.sum << '\n';

Using lambda expressions as predicates

std::vector<int> nums{3, 4, 2, 8, 15, 267};
void (*pfunc)(const int &) = for_each(nums.begin(), nums.end(), [](const int &n) { 																	cout << n << " "; });
cout << endl;
pfunc(7);

Calculate function

The aggregate function is defined in the numeric header file. There are two types of function definitions:

The first implementation is to accumulate the elements in the range of [first, last], init+=*first, and return the accumulation result

template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init)
{
    for (; first != last; ++first) {
        init = std::move(init) + *first; // std::move since C++20
    }
    return init;
}

The second implementation is different from the accumulation rule. The accumulation rule can be defined in the predicate, init = op(std::move(init), *first) and return the accumulation result

template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init, 
             BinaryOperation op)
{
    for (; first != last; ++first) {
        init = op(std::move(init), *first); // std::move since C++20
    }
    return init;
}

Using functions as predicates

// Pay attention to the order of lhs and rhs!!!
int op_sum(int total, int value) {
    return total + value * value;
}

vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
// Use default accumulation
cout << accumulate(v.begin(), v.end(), 0) << endl;
// Use functions as predicates to calculate the sum of squares
cout << accumulate(v.begin(), v.end(), 0, op_sum) << endl;

Using function objects as predicates

template<typename T>
class OpSum {
private:
    int power;
public:
    explicit OpSum(int p) : power(p) {}

    T operator()(const T &total, const T &value) {  //Calculate the power of value and add it to total
        return total + pow(value, power);
    }
};


vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
// Use default accumulation
cout << accumulate(v.begin(), v.end(), 0) << endl;
// Use the function object as the predicate to calculate the sum of squares
cout << accumulate(v.begin(), v.end(), 0, OpSum<int>(2)) << endl;

Using lambda expressions as predicates

vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
// Use default accumulation
cout << accumulate(v.begin(), v.end(), 0) << endl;

// Use lambda as the predicate to calculate the sum of squares
cout << accumulate(v.begin(), v.end(), 0, [](const int &total, const int &value) { return total + value * value; })
    << endl;

For some simple requirements, we can use the default accumulation or lambda expression to solve them in one line. Of course, if more complex requirements are needed, such as various accumulation rules, and even want to accumulate rules for different data types, it is recommended to use function objects.

All codes are as follows:

//Function object
#include <iostream>
#include <vector>
#Include < numeric > / / accumulate is defined in this header file
#include <algorithm>
#include <cmath>

using namespace std;

// Pay attention to the order of lhs and rhs!!!
int op_sum(int total, int value) {
    return total + value * value;
}

template<typename T>
class OpSum {
private:
    int power;
public:
    explicit OpSum(int p) : power(p) {}

    T operator()(const T &total, const T &value) {  //Calculate the power of value and add it to total
        return total + pow(value, power);
    }
};

int main() {
    vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for_each(v.begin(), v.end(), [](const int &n) { cout << n << " "; });
    // Use default accumulation
    cout << accumulate(v.begin(), v.end(), 0) << endl;
    // Use functions as predicates to calculate the sum of squares
    cout << accumulate(v.begin(), v.end(), 0, op_sum) << endl;
    // Use the function object as the predicate to calculate the sum of squares
    cout << accumulate(v.begin(), v.end(), 0, OpSum<int>(2)) << endl;
    // Use lambda as the predicate to calculate the sum of squares
    cout << accumulate(v.begin(), v.end(), 0, [](const int &total, const int &value) { return total + value * value; })
         << endl;
    return 0;
}

contrast

for_each accumulate
predicate Only one parameter is required, and the processing of parameters does not need to be associated with other elements in the [first, last] range Two parameters (init,value) are required to be associated with the processing of elements in the range
Return results Returns the predicate, in which the processing results can be stored Return the accumulation result
summary Make some transformation adjustment to the elements in the range It is often used to accumulate the mapping of elements within the calculation range

Posted by Nymphetamine on Fri, 03 Dec 2021 22:31:54 -0800