Reputation: 4642
I have been looking for a more optimal solution to the following and I cannot seem to find one.
Let's say I have a vector:
std::vector<double> vars = {1, 2, 3}
I want to perform 1 * 2 * 3
I know that I can do the following:
int multi = 1;
for(int i = 0; (i < vars.size()-1); i++)
{
multi *= vars[i];
}
But, is there a more "C++11" way to do this? I really wanted to do this using lambda
and so that I can calculate the multiply (product) of the vector without having another function inside the class, I'd rather have it calculated inside the function.
Upvotes: 25
Views: 41905
Reputation: 61920
Yes, as usual, there is an algorithm (though this one's in <numeric>
), std::accumulate
(live example):
using std::begin;
using std::end;
double multi = std::accumulate(begin(vars), end(vars), 1.0, std::multiplies<double>());
std::multiplies
is in <functional>
, too. By default, std::accumulate
uses std::plus
, which adds two values given to operator()
. std::multiplies
multiplies them instead.
The C++23 ranges version of this function is std::ranges::fold_left
. In addition, CTAD and improvements to the standard "operator objects" have made them nicer to use:
namespace rng = std::ranges;
auto multi = rng::fold_left(vars, 1.0, std::multiplies());
As a side note, C++17 also added std::reduce
, which is permitted to do operations out of order for speed. There is currently no ranges version of this.
Upvotes: 56
Reputation: 12751
Another way is using inclusive_scan
(C++17 and above)
The advantage is you can get multiplies of first "N" elements in a vector. Below is the code. Explanation in comments.
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
//INPUT VECTOR
std::vector<int> data{ 3, 1, 4, 1, 5, 9, 2, 6 };
//OUTPUT VECTOR WITH MULTIPLIES
//FIRST ELEMENT - 3
//SECOND ELEMENT - 3 * 1
//THIRD ELEMENT - 3 * 1 * 4
//FOURTH ELEMENT - 3 * 1 * 4 * 1
// ..
// ..
//LAST ELEMENT - 3 * 1 * 4 * 1 * 5 * 9 * 2 * 6
std::vector<int> multiplies(data.size());
//Multiply all numbers in given vector.
inclusive_scan(data.begin(), data.end(),
multiplies.begin(),
std::multiplies<>{});
//PRODUCT OF FIRST 5 ELEMENTS.
std::cout << "Product of first 5 elements :: " << multiplies[4] << std::endl;
//PRODUCT OF ALL ELEMENTS
std::cout << "Product of all elements :: " << multiplies[data.size() - 1] << std::endl;
}
Also there is an overload where the execution policy can be specified. Sequential execution or Parallel execution. Need to include "execution" header.
//MULTIPLY ALL NUMBERS IN VECTOR WITH PARALLEL EXECUTION.
inclusive_scan(std::execution::par,data.begin(), data.end(),
multiplies.begin(),
std::multiplies<>{});
Upvotes: 0
Reputation: 180630
You can use a ranged based for loop like:
std::vector<double> vars = {1, 2, 3}
int multi = 1;
for (const auto& e: vars)
multi *= e;
Upvotes: 7