I'm trying to implement cartesian product using a closure / custom function, the closure is function(x,y) = pow(x,2) + pow(y,2)
and implement it the functional way i.e. without using the C-style loops.
Here is my take.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
void print (vector<int> aux) {
vector<int>::iterator it = aux.begin();
while(it != aux.end()){
cout << *it << " ";
it++; }}
int main() {
vector<int> a{1,2};
vector<int> b{3,4};
vector<int> cartesian(4);
transform (a.begin(), a.end(), b.begin(), cartesian.begin(), [](int &i)
{vector<int>::iterator p = b.begin();
for_each(begin(b), end(b), [](int &n) { return pow(i,2) + pow(n,2) })});
print(cartesian);
// desired output is: 10,17,13,20 (cartesian operation)
}
First, using each element of the first vector, iterate over the second vector , then store the result of applying the function in the result vector.
The code is for representation purposes. It doesn't compile. It gives 'b' is not captured in {vector<int>::iterator p = b.begin();
error, among others.
How to rectify this code and/or how to correctly implement cartesian operation with a closure?
Your compilation issues are because you are not capturing the needed variables in your lambdas, and you're missing some ;
.
However, a simpler way to do a cartesian product is with 2 nested loops, like this:
for (int i : a)
for (int j : b)
cartesian.push_back(i * i + j * j);
If you want to use algorithms, then you can write:
for_each(begin(a), end(a), [&](int i) {
for_each(begin(b), end(b), [&](int j) {
cartesian.push_back(i * i + j * j);
});
});
although I find this harder to read, and doesn't really help much since for_each
is an algorithm that happens to have an in-built language construct, similar to transform
.
From c++20, ranges and views have been added, and so you can get considerably more creative:
namespace rs = std::ranges;
namespace rv = std::views;
auto product = [=](int i)
{
auto op = [=](int j) { return i * i + j * j;};
return b | rv::transform(op);
};
rs::copy(a | rv::transform(product)
| rv::join,
std::back_inserter(cartesian));
Again, the original nested for
loops are probably the best approach for a cartesian product, but this should give you a taste for the exciting possibilities.
Here's a demo.