我正在摆弄下面的 Rcpp 代码,它的工作方式类似于 R 的 expand.grid()。目标是采用未知数量的任何数据类的输入向量,并输出所有输入的组合。例如,给定
a<-c(1,2)
和b<-c(3,4,5)
,函数combine_vectors(list(a,b))
返回:
v1 v2
1 1 3
2 1 4
3 1 5
4 2 3
5 2 4
6 2 5
我让它为数字输入向量工作,但我终究无法弄清楚如何处理字符串和数字向量。看来我需要做的关键改变是
std::vector<std::vector<int>*> combo_vectors;
是通用的(而不是 <int>
)或根据大小写切换。理想情况下,我想在 C++ 中进行类型检查。
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
DataFrame combine_vectors(List vectors) {
int num_vectors = vectors.length();
std::vector<int> indices(num_vectors, 0);
std::vector<std::vector<int>*> combo_vectors;
for (int i = 0; i < num_vectors; i++) {
combo_vectors.push_back(new std::vector<int>());
}
bool done = false;
while (!done) {
for (int i = 0; i < num_vectors; i++) {
SEXP vector = vectors[i];
switch (TYPEOF(vector)) {
case INTSXP:
combo_vectors[i]->push_back(IntegerVector(vector)[indices[i]]);
break;
case REALSXP:
combo_vectors[i]->push_back(NumericVector(vector)[indices[i]]);
break;
default:
Rcpp::stop("unsupported vector type");
}
}
int i = num_vectors - 1;
while (i >= 0) {
indices[i]++;
if (indices[i] == Rf_length(vectors[i])) {
indices[i] = 0;
i--;
} else {
break;
}
}
if (i < 0) {
done = true;
}
}
int num_combos = combo_vectors[0]->size();
List output(num_vectors);
CharacterVector col_names(num_vectors);
for (int i = 0; i < num_vectors; i++) {
switch (TYPEOF(vectors[i])) {
case INTSXP: {
IntegerVector col(num_combos);
for (int j = 0; j < num_combos; j++) {
col[j] = (*combo_vectors[i])[j];
}
output[i] = col;
break;
}
case REALSXP: {
NumericVector col(num_combos);
for (int j = 0; j < num_combos; j++) {
col[j] = (*combo_vectors[i])[j];
}
output[i] = col;
break;
}
default:
Rcpp::stop("unsupported vector type");
}
col_names[i] = std::string("v") + std::to_string(i + 1);
delete combo_vectors[i];
}
output.attr("names") = col_names;
DataFrame df(output);
return df;
}
编辑: 我想我的问题是如何添加字符串向量?当我为 STRSXP 添加大小写切换时,我收到错误消息“没有匹配函数来调用‘push_back(Rcpp::Vector<16>::Proxy)”这是无效代码。
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
DataFrame combine_vectors1(List vectors) {
int num_vectors = vectors.length();
std::vector<int> indices(num_vectors, 0);
std::vector <std::vector<int>*>combo_vectors;
for (int i = 0; i < num_vectors; i++) {
combo_vectors.push_back(new std::vector<int>());
}
bool done = false;
while (!done) {
for (int i = 0; i < num_vectors; i++) {
SEXP vector = vectors[i];
switch (TYPEOF(vector)) {
case INTSXP:
combo_vectors[i]->push_back(IntegerVector(vector)[indices[i]]);
break;
case REALSXP:
combo_vectors[i]->push_back(NumericVector(vector)[indices[i]]);
break;
case STRSXP:
combo_vectors[i]->push_back(CharacterVector(vector)[indices[i]]);
break;
default:
Rcpp::stop("unsupported vector type");
}
}
int i = num_vectors - 1;
while (i >= 0) {
indices[i]++;
if (indices[i] == Rf_length(vectors[i])) {
indices[i] = 0;
i--;
} else {
break;
}
}
if (i < 0) {
done = true;
}
}
int num_combos = combo_vectors[0]->size();
List output(num_vectors);
CharacterVector col_names(num_vectors);
for (int i = 0; i < num_vectors; i++) {
switch (TYPEOF(vectors[i])) {
case INTSXP: {
IntegerVector col(num_combos);
for (int j = 0; j < num_combos; j++) {
col[j] = (*combo_vectors[i])[j];
}
output[i] = col;
break;
}
case REALSXP: {
NumericVector col(num_combos);
for (int j = 0; j < num_combos; j++) {
col[j] = (*combo_vectors[i])[j];
}
output[i] = col;
break;
}
case STRSXP: {
CharacterVector col(num_combos);
for (int j = 0; j < num_combos; j++) {
col[j] = (*combo_vectors[i])[j];
}
output[i] = col;
break;
}
default:
Rcpp::stop("unsupported vector type");
}
col_names[i] = std::string("v") + std::to_string(i + 1);
delete combo_vectors[i];
}
output.attr("names") = col_names;
DataFrame df(output);
return df;