我会编写一个函数(使用Rcpp),NA从R向量中删除所有值.
在这之前,我通过Rcpp::cppFunction功能做了一点测试功能.
library(inline)
cppFunction('
Vector<INTSXP> na_test(const Vector<INTSXP>& x) {
return setdiff(x, Vector<INTSXP>::create(::traits::get_na<INTSXP>()));
}
')
Run Code Online (Sandbox Code Playgroud)
这是这样的:
na_test(c(1, NA, NA, 1, 2, NA))
# [1] 1 2
Run Code Online (Sandbox Code Playgroud)
之后我尝试通过C++ 模板机制推广这个功能.
所以,在外部的.cpp文件(通过sourceCpp函数获取)中,我写道:
template <int RTYPE>
Vector<RTYPE> na_test_template(const Vector<RTYPE>& x) {
return setdiff(x, Vector<RTYPE>::create(::traits::get_na<RTYPE>()));
}
// [[Rcpp::export(na_test_cpp)]]
SEXP na_test(SEXP x) {
switch(TYPEOF(x)) {
case INTSXP:
return na_test_template<INTSXP>(x);
case REALSXP:
return na_test_template<REALSXP>(x);
}
return R_NilValue;
}
Run Code Online (Sandbox Code Playgroud)
这段代码编译但行为不同,我无法解释原因.
事实上:
na_test_cpp(c(1, NA, NA, 1, 2, NA))
# [1] 2 NA NA NA 1
Run Code Online (Sandbox Code Playgroud)
为什么相同的功能(显然)表现不同?这里发生了什么?
按照你的答案,我会使用这样的东西作为模板:
template <int RTYPE>
Vector<RTYPE> na_omit_template(const Vector<RTYPE>& x) {
int n = x.size() ;
int n_out = n - sum( is_na(x) ) ;
Vector<RTYPE> out(n_out) ;
for( int i=0, j=0; i<n; i++){
if( Vector<RTYPE>::is_na( x[i] ) ) continue ;
out[j++] = x[i];
}
return out ;
}
Run Code Online (Sandbox Code Playgroud)
所以我们的想法是先计算结果的长度,然后再使用Rcpp向量类代替std::vector.这将导致更少的数据副本.
使用Rcpp(svn revision> = 4308)的开发版本,它适用于所有类型的我,然后我们可以使用我们的RCPP_RETURN_VECTOR调度宏而不是编写switch:
// [[Rcpp::export]]
SEXP na_omit( SEXP x ){
RCPP_RETURN_VECTOR( na_omit_template, x ) ;
}
Run Code Online (Sandbox Code Playgroud)
na_omit已被包含在Rcpp(svn revision> = 4309)中,只有一些修改,即它可以处理命名向量和任意糖表达式.