在 C++ 中嵌入 R:访问 VECSXP 的元素
Embedding R in C++: access elements of a VECSXP
所以我从 C++ 调用了一些 R 代码,为此我直接调用了 R.dll(我知道 Rcpp,我桌上有这本书,但我可以'不要将它用于这个特定的东西)。我有一个设置变量的 R 脚本,我想访问该变量的内容。
变量是字符串列表;在 C++ 中,当我执行 TYPEOF(my_sexp) 时,我得到 VECSXP;到目前为止,一切都很好。现在我想将该列表的内容读入 std::vector。我尝试了以下想法的许多排列:
SEXP vector_exp = VECTOR_ELT(my_sexp, 0);
int element_count = TRUELENGTH(vector_exp);
for (int i = 0 ; i < element_count ; i++) {
SEXP elem_sexp = VECTOR_ELT(my_sexp, i);
std::string element_string = R_CHAR(elem_sexp);
}
我的问题:
- 使用 TRUELENGTH,我可以访问冲突。使用 LENGTH,我得到了一个错误的值。
- 使用 VECTOR_ELT() 访问列表元素会导致访问冲突。
- 我已经尝试根据 R headers 中的结构定义手动检查 my_sexp 的内存布局,但我似乎无法正确地进行转换以从中获取有意义的值。
所以,有没有人能大致告诉我如何访问列表的元素;或者给我举个例子;或指向 Rcpp 中完成此类转换的位置?我试着自己找到最后一点,但没走多远——Rcpp 的 wrap() 似乎以某种方式处理了它 'magically'(一般来说)。
提前致谢。
我没有花太多时间使用 R 的 C 接口,因为我通常坚持使用 Rcpp,但以下似乎有效:
#include <Rcpp.h>
// [[Rcpp::export]]
void print_list_as_vector(SEXP lst) {
PROTECT(lst);
R_xlen_t n_list = XLENGTH(lst);
R_xlen_t n_elem = 0;
for (R_xlen_t i = 0; i < n_list; i++) {
n_elem += XLENGTH(VECTOR_ELT(lst, i));
}
std::vector<std::string> vs;
vs.reserve(n_elem);
for (R_xlen_t i = 0; i < n_list; i++) {
R_xlen_t nj = XLENGTH(VECTOR_ELT(lst, i));
for (R_xlen_t j = 0; j < nj; j++) {
vs.push_back(CHAR(STRING_ELT(VECTOR_ELT(lst, i), j)));
}
}
for (std::size_t i = 0; i < vs.size(); i++) {
Rcpp::Rcout <<
vs[i] << std::endl;
}
UNPROTECT(1);
}
/*** R
clist <- list(c("a", "b", "c"), c("l", "m", "n", "o", "p"), c("xyz1", "xyz2"))
print_list_as_vector(clist)
#a
#b
#c
#l
#m
#n
#o
#p
#xyz1
#xyz2
unlist(clist)
# [1] "a" "b" "c" "l" "m" "n" "o" "p" "xyz1" "xyz2"
*/
如您所见,这是在 R 中测试的/使用 Rcpp 属性,但在实际的代码中,我试图坚持使用 C 接口来复制您的情况。
但为了解决您的问题(尽我所能)-
- 我一直使用
XLENGTH
来获取SEXP
的长度,虽然我不能真正说出XLENGTH
、LENGTH
和LENGTH
之间的区别TRUELENGTH
,第一种方法似乎总能产生预期的结果。
- 我正在使用
VECTOR_ELT(lst, i)
访问 VECSXP
lst
中的第 i 个元素。
- 鉴于数据/函数的上下文,我知道
VECTOR_ELT(lst, i)
正在返回一个 STRSXP
- 即一个字符向量。这个STRSXP
的第j个元素是用STRING_ELT(..., j)
访问的,由于这个returns一个CHARSXP
,我们把它包在CHAR
中得到一个const char*
,它被添加到 std::vector<std::string>
。
不幸的是,似乎没有 很多关于 R 的 C 内部结构的文档,但是 Hadley 有一个有用的 reference page here, and if all else fails, you can dig through the source itself.
所以我从 C++ 调用了一些 R 代码,为此我直接调用了 R.dll(我知道 Rcpp,我桌上有这本书,但我可以'不要将它用于这个特定的东西)。我有一个设置变量的 R 脚本,我想访问该变量的内容。
变量是字符串列表;在 C++ 中,当我执行 TYPEOF(my_sexp) 时,我得到 VECSXP;到目前为止,一切都很好。现在我想将该列表的内容读入 std::vector。我尝试了以下想法的许多排列:
SEXP vector_exp = VECTOR_ELT(my_sexp, 0);
int element_count = TRUELENGTH(vector_exp);
for (int i = 0 ; i < element_count ; i++) {
SEXP elem_sexp = VECTOR_ELT(my_sexp, i);
std::string element_string = R_CHAR(elem_sexp);
}
我的问题: - 使用 TRUELENGTH,我可以访问冲突。使用 LENGTH,我得到了一个错误的值。 - 使用 VECTOR_ELT() 访问列表元素会导致访问冲突。 - 我已经尝试根据 R headers 中的结构定义手动检查 my_sexp 的内存布局,但我似乎无法正确地进行转换以从中获取有意义的值。
所以,有没有人能大致告诉我如何访问列表的元素;或者给我举个例子;或指向 Rcpp 中完成此类转换的位置?我试着自己找到最后一点,但没走多远——Rcpp 的 wrap() 似乎以某种方式处理了它 'magically'(一般来说)。
提前致谢。
我没有花太多时间使用 R 的 C 接口,因为我通常坚持使用 Rcpp,但以下似乎有效:
#include <Rcpp.h>
// [[Rcpp::export]]
void print_list_as_vector(SEXP lst) {
PROTECT(lst);
R_xlen_t n_list = XLENGTH(lst);
R_xlen_t n_elem = 0;
for (R_xlen_t i = 0; i < n_list; i++) {
n_elem += XLENGTH(VECTOR_ELT(lst, i));
}
std::vector<std::string> vs;
vs.reserve(n_elem);
for (R_xlen_t i = 0; i < n_list; i++) {
R_xlen_t nj = XLENGTH(VECTOR_ELT(lst, i));
for (R_xlen_t j = 0; j < nj; j++) {
vs.push_back(CHAR(STRING_ELT(VECTOR_ELT(lst, i), j)));
}
}
for (std::size_t i = 0; i < vs.size(); i++) {
Rcpp::Rcout <<
vs[i] << std::endl;
}
UNPROTECT(1);
}
/*** R
clist <- list(c("a", "b", "c"), c("l", "m", "n", "o", "p"), c("xyz1", "xyz2"))
print_list_as_vector(clist)
#a
#b
#c
#l
#m
#n
#o
#p
#xyz1
#xyz2
unlist(clist)
# [1] "a" "b" "c" "l" "m" "n" "o" "p" "xyz1" "xyz2"
*/
如您所见,这是在 R 中测试的/使用 Rcpp 属性,但在实际的代码中,我试图坚持使用 C 接口来复制您的情况。
但为了解决您的问题(尽我所能)-
- 我一直使用
XLENGTH
来获取SEXP
的长度,虽然我不能真正说出XLENGTH
、LENGTH
和LENGTH
之间的区别TRUELENGTH
,第一种方法似乎总能产生预期的结果。 - 我正在使用
VECTOR_ELT(lst, i)
访问VECSXP
lst
中的第 i 个元素。 - 鉴于数据/函数的上下文,我知道
VECTOR_ELT(lst, i)
正在返回一个STRSXP
- 即一个字符向量。这个STRSXP
的第j个元素是用STRING_ELT(..., j)
访问的,由于这个returns一个CHARSXP
,我们把它包在CHAR
中得到一个const char*
,它被添加到std::vector<std::string>
。
不幸的是,似乎没有 很多关于 R 的 C 内部结构的文档,但是 Hadley 有一个有用的 reference page here, and if all else fails, you can dig through the source itself.