在 C++17 中以函数式方式做笛卡尔积
Doing cartesian product the functional way in C++17
我正在尝试使用闭包/自定义函数实现笛卡尔积,闭包是 function(x,y) = pow(x,2) + pow(y,2)
并以功能方式实现它,即不使用 C 风格的循环。
这是我的看法。
#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)
}
首先,使用第一个向量的每个元素迭代第二个向量,然后将应用该函数的结果存储在结果向量中。
该代码用于表示目的。它不编译。它给出 'b' is not captured in {vector<int>::iterator p = b.begin();
错误,等等。
如何改正此代码and/or如何使用闭包正确实现笛卡尔运算?
您的编译问题是因为您没有在您的 lambda 中捕获所需的变量,并且您遗漏了一些 ;
。
但是,做笛卡尔积的更简单方法是使用 2 个嵌套循环,如下所示:
for (int i : a)
for (int j : b)
cartesian.push_back(i * i + j * j);
如果要使用算法,那么可以这样写:
for_each(begin(a), end(a), [&](int i) {
for_each(begin(b), end(b), [&](int j) {
cartesian.push_back(i * i + j * j);
});
});
尽管我觉得这更难阅读,而且并没有多大帮助,因为 for_each
是一种恰好具有 in-built 语言结构的算法,类似于 transform
。
从 c++20 开始,添加了范围和视图,因此您可以获得更多创意:
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));
同样,最初的嵌套 for
循环可能是笛卡尔积的最佳方法,但这应该让您体验到令人兴奋的可能性。
这里是 demo。
我正在尝试使用闭包/自定义函数实现笛卡尔积,闭包是 function(x,y) = pow(x,2) + pow(y,2)
并以功能方式实现它,即不使用 C 风格的循环。
这是我的看法。
#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)
}
首先,使用第一个向量的每个元素迭代第二个向量,然后将应用该函数的结果存储在结果向量中。
该代码用于表示目的。它不编译。它给出 'b' is not captured in {vector<int>::iterator p = b.begin();
错误,等等。
如何改正此代码and/or如何使用闭包正确实现笛卡尔运算?
您的编译问题是因为您没有在您的 lambda 中捕获所需的变量,并且您遗漏了一些 ;
。
但是,做笛卡尔积的更简单方法是使用 2 个嵌套循环,如下所示:
for (int i : a)
for (int j : b)
cartesian.push_back(i * i + j * j);
如果要使用算法,那么可以这样写:
for_each(begin(a), end(a), [&](int i) {
for_each(begin(b), end(b), [&](int j) {
cartesian.push_back(i * i + j * j);
});
});
尽管我觉得这更难阅读,而且并没有多大帮助,因为 for_each
是一种恰好具有 in-built 语言结构的算法,类似于 transform
。
从 c++20 开始,添加了范围和视图,因此您可以获得更多创意:
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));
同样,最初的嵌套 for
循环可能是笛卡尔积的最佳方法,但这应该让您体验到令人兴奋的可能性。
这里是 demo。