这是一种可能的方法:
#include <Rcpp.h>
Rcpp::LogicalVector logical_index(Rcpp::IntegerVector idx, R_xlen_t n) {
bool invert = false;
Rcpp::LogicalVector result(n, false);
for (R_xlen_t i = 0; i < idx.size(); i++) {
if (!invert && idx[i] < 0) invert = true;
result[std::abs(idx[i])] = true;
}
if (!invert) return result;
return !result;
}
// [[Rcpp::export]]
Rcpp::NumericVector
Subset(Rcpp::NumericVector x, Rcpp::IntegerVector idx) {
return x[logical_index(idx, x.size())];
}
x <- seq(2, 10, 2)
x[c(2, 4)]
#[1] 4 8
Subset(x, c(1, 3))
#[1] 4 8
x[-c(2, 4)]
#[1] 2 6 10
Subset(x, -c(1, 3))
#[1] 2 6 10
请注意,Rcpp 函数的索引是从 0 开始的,因为它们是在 C++ 中处理的。
我将子集逻辑抽象为它自己的函数,logical_index
,它将转换为IntegerVector
to a LogicalVector
为了能够“决定”是否删除或保留指定的元素(例如通过反转结果)。我想这也可以通过基于整数的子集来完成,但无论哪种方式都不重要。
就像 R 中的向量子集一样,向量all负索引表示删除对应的元素;而所有正索引的向量表示要保留的元素。我没有检查混合情况,这可能会抛出异常,就像 R 会做的那样。
关于我的最后评论,依靠 Rcpp 的本机重载进行普通子集设置可能更明智,并且有一个用于否定子集设置的专用函数(R 的x[-c(...)]
构造),而不是像上面那样混合功能。有预先存在的糖表达式用于创建这样的函数,例如
#include <Rcpp.h>
template <int RTYPE>
inline Rcpp::Vector<RTYPE>
anti_subset(const Rcpp::Vector<RTYPE>& x, Rcpp::IntegerVector idx) {
Rcpp::IntegerVector xi = Rcpp::seq(0, x.size() - 1);
return x[Rcpp::setdiff(xi, idx)];
}
// [[Rcpp::export]]
Rcpp::NumericVector
AntiSubset(Rcpp::NumericVector x, Rcpp::IntegerVector idx) {
return anti_subset(x, idx);
}
/*** R
x <- seq(2, 10, 2)
x[-c(2, 4)]
#[1] 2 6 10
AntiSubset(x, c(1, 3))
#[1] 2 6 10
*/