创建一个模板函数以根据大小用另一个向量填充另一个向量
Creating a Templated Function to Fill a Vector with another depending on Size
Rcpp 中是否有一个基本函数:
- 如果向量的大小为 1,则完全由单个值填充。
- 如果长度相同,则完全填充另一个向量。
- 如果向量长度不相同且向量大小为 1,则用
NA
值填充。
我以 NumericVector
为例,将上述条件编写为函数。如果 Rcpp 中没有执行上述操作的基本函数,则应该有一种方法来模板化该函数,以便给定任何类型的向量(例如 numeric
、character
等)上述逻辑将能够被执行。
// [[Rcpp::export]]
NumericVector cppvectorize(NumericVector x,NumericVector y) {
NumericVector y_out(y.size());
if(x.size() == 1) {
for(int i = 0; i < y_out.size(); i++) {
y_out[i] = x[0];
}
} else if(x.size() == y_out.size()) {
for(int i = 0; i < y_out.size(); i++) {
y_out[i] = x[i];
}
} else {
for(int i = 0; i < y_out.size(); i++) {
y_out[i] = NA_REAL;
}
}
return y_out;
}
不幸的是,最接近此类功能的是 Rcpp 支持的 rep
变体之一。但是,none 个变体与所需的输出相匹配。因此,唯一的选择是真正实现所需功能的模板化版本。
要创建模板函数,我们将首先创建一个路由函数来处理可能的 SEXP
objects. The rationale behind the routing function is SEXP
objects are able to be retrieved from and surfaced into R using Rcpp Attributes whereas a templated version is not. As a result, we need to specify the SEXTYPE (used as RTYPE) 分派。 TYPEOF()
宏检索编码数字。使用 switch
语句,我们可以将这个数字分配到适当的案例中。
调度后,我们到达了模板函数。模板化函数利用 Rcpp 的基础 Vector
class 来简化数据流。从这里开始,值得注意的新颖之处在于使用 ::traits::get_na<RTYPE>()
动态检索适当的 NA
值并填充它。
计划好了,我们来看代码:
#include <Rcpp.h>
using namespace Rcpp;
// ---- Templated Function
template <int RTYPE>
Vector<RTYPE> vec_helper(const Vector<RTYPE>& x, const Vector<RTYPE>& y) {
Vector<RTYPE> y_out(y.size());
if(x.size() == 1){
y_out.fill(x[0]);
} else if (x.size() == y.size()) {
y_out = x;
} else {
y_out.fill(::traits::get_na<RTYPE>());
}
return y_out;
}
// ---- Dispatch function
// [[Rcpp::export]]
SEXP cppvectorize(SEXP x, SEXP y) {
switch (TYPEOF(x)) {
case INTSXP: return vec_helper<INTSXP>(x, y);
case REALSXP: return vec_helper<REALSXP>(x, y);
case STRSXP: return vec_helper<STRSXP>(x, y);
default: Rcpp::stop("SEXP Type Not Supported.");
}
// Need to return a value even though this will never be triggered
// to quiet the compiler.
return R_NilValue;
}
样本测试
这里我们对每个支持的数据进行一些样本测试
# Case 1: x == 1
x = 1:5
y = 2
cppvectorize(x, y)
## [1] NA
# Case 2: x == y
x = letters[1:5]
y = letters[6:10]
cppvectorize(x, y)
## [1] "a" "b" "c" "d" "e"
# Case 3: x != y && x > 1
x = 1.5
y = 2.5:6.5
cppvectorize(x, y)
## [1] 1.5 1.5 1.5 1.5 1.5
Rcpp 中是否有一个基本函数:
- 如果向量的大小为 1,则完全由单个值填充。
- 如果长度相同,则完全填充另一个向量。
- 如果向量长度不相同且向量大小为 1,则用
NA
值填充。
我以 NumericVector
为例,将上述条件编写为函数。如果 Rcpp 中没有执行上述操作的基本函数,则应该有一种方法来模板化该函数,以便给定任何类型的向量(例如 numeric
、character
等)上述逻辑将能够被执行。
// [[Rcpp::export]]
NumericVector cppvectorize(NumericVector x,NumericVector y) {
NumericVector y_out(y.size());
if(x.size() == 1) {
for(int i = 0; i < y_out.size(); i++) {
y_out[i] = x[0];
}
} else if(x.size() == y_out.size()) {
for(int i = 0; i < y_out.size(); i++) {
y_out[i] = x[i];
}
} else {
for(int i = 0; i < y_out.size(); i++) {
y_out[i] = NA_REAL;
}
}
return y_out;
}
不幸的是,最接近此类功能的是 Rcpp 支持的 rep
变体之一。但是,none 个变体与所需的输出相匹配。因此,唯一的选择是真正实现所需功能的模板化版本。
要创建模板函数,我们将首先创建一个路由函数来处理可能的 SEXP
objects. The rationale behind the routing function is SEXP
objects are able to be retrieved from and surfaced into R using Rcpp Attributes whereas a templated version is not. As a result, we need to specify the SEXTYPE (used as RTYPE) 分派。 TYPEOF()
宏检索编码数字。使用 switch
语句,我们可以将这个数字分配到适当的案例中。
调度后,我们到达了模板函数。模板化函数利用 Rcpp 的基础 Vector
class 来简化数据流。从这里开始,值得注意的新颖之处在于使用 ::traits::get_na<RTYPE>()
动态检索适当的 NA
值并填充它。
计划好了,我们来看代码:
#include <Rcpp.h>
using namespace Rcpp;
// ---- Templated Function
template <int RTYPE>
Vector<RTYPE> vec_helper(const Vector<RTYPE>& x, const Vector<RTYPE>& y) {
Vector<RTYPE> y_out(y.size());
if(x.size() == 1){
y_out.fill(x[0]);
} else if (x.size() == y.size()) {
y_out = x;
} else {
y_out.fill(::traits::get_na<RTYPE>());
}
return y_out;
}
// ---- Dispatch function
// [[Rcpp::export]]
SEXP cppvectorize(SEXP x, SEXP y) {
switch (TYPEOF(x)) {
case INTSXP: return vec_helper<INTSXP>(x, y);
case REALSXP: return vec_helper<REALSXP>(x, y);
case STRSXP: return vec_helper<STRSXP>(x, y);
default: Rcpp::stop("SEXP Type Not Supported.");
}
// Need to return a value even though this will never be triggered
// to quiet the compiler.
return R_NilValue;
}
样本测试
这里我们对每个支持的数据进行一些样本测试
# Case 1: x == 1
x = 1:5
y = 2
cppvectorize(x, y)
## [1] NA
# Case 2: x == y
x = letters[1:5]
y = letters[6:10]
cppvectorize(x, y)
## [1] "a" "b" "c" "d" "e"
# Case 3: x != y && x > 1
x = 1.5
y = 2.5:6.5
cppvectorize(x, y)
## [1] 1.5 1.5 1.5 1.5 1.5