Home > Net >  How to use std::acumulate for matrix
How to use std::acumulate for matrix

Time:01-01

#include <iostream>
#include <numeric>
#include <vector>


using matrix = std::vector<std::vector<int>>;

int main()
{
    matrix mtx{5, std::vector<int>(5)};

    int sum = 0;
    for (const auto i : mtx) // can be avoided ? 
    sum  = std::accumulate(i.begin(), i.end(), 0, 
        [](int a, int b){a > 0 ? a   b : a;});

}

I want to use std::accumulate for std::vector<std::vector<int>> but I am curious if I can avoid the loop. Also I want to know if the last argument is ok.

CodePudding user response:

Based on your lambda, looks like you want to just sum the positive entries:

#include <iostream>
#include <numeric>
#include <vector>

using Number = int;
using Matrix = std::vector<std::vector<Number>>;

int main() {
  Matrix mtx{5, std::vector<Number>(5, 1)};

  Number sum_positives = std::accumulate(
      mtx.begin(), mtx.end(), Number(0), [](Number const acc, auto const &v) {
        return std::accumulate(
            v.begin(), v.end(), acc,
            [](Number const a, Number const b) { return b > 0 ? a   b : a; });
      });

  std::cout << sum_positives << std::endl;  // 25
  return 0;
}

Don't forget that the lambda you pass to std::accumulate() must return a value.

CodePudding user response:

C 20 ranges' join_views are especially useful for this, since they allow you to flatten a matrix into a vector.

So you end up with a code like:

int sum{0};
auto jv{ std::ranges::join_view(mtx) };  // flatten mtx into a list of ints
std::ranges::for_each(jv, [&sum](auto n) { sum  = n; });

For a full sample filling the matrix with random numbers between [-100, 100]:

[Demo]

#include <algorithm>  // fill, for_each
#include <iostream>  // cout
#include <random>
#include <ranges>  // for_each, join_view
#include <vector>

using matrix = std::vector<std::vector<int>>;

int main()
{
    matrix mtx{3, std::vector<int>(3)};

    // Fill matrix with random values between [-100, 100]
    std::default_random_engine re{ std::random_device{}() };
    std::uniform_int_distribution<int> dist{ -100, 100 };
    std::for_each(std::begin(mtx), std::end(mtx),
        [&dist, &re](auto& row) {
            std::for_each(std::begin(row), std::end(row),
                [&dist, &re](auto& n) { n = dist(re); }
            );
        }
    );

    auto jv{ std::ranges::join_view(mtx) };  // flatten mtx into a list of ints
    
    // Print matrix
    std::cout << "mtx = ";
    std::ranges::for_each(jv, [](auto n) { std::cout << n << " "; });
    std::cout << "\n";

    // Sum all positive values in the matrix    
    int sum{0};
    std::ranges::for_each(jv, [&sum](auto n) { sum  = ((n >= 0) ? n : 0); });
    std::cout << "sum = " << sum << "\n";
}
  • Related