我们说我有一个向量[2,4,6,8,10],我需要从这个向量中删除第二个和第四个元素。所需的结果载体应为[2,6,10]。这很容易在R中实现:
$json = json_decode($content); // without true
echo $json->rows[0]->elements[0]->duration->text;
但是我如何在Rcpp / RcppArmadillo中实现这个呢?我可以通过使用v1 <- c(2,4,6,8,10)
v1[-c(2,4)]
函数找出连续的情况(即删除第2个到第4个元素),但不连续的情况对我来说似乎不那么明显因为.erase()
似乎不接受.erase
类型的向量。速度可能是一个考虑因素,因为在我的应用程序中v1可能非常大。
答案 0 :(得分:1)
这是一种可行的方法:
#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
转换为LogicalVector
,以便能够“决定”是否删除或保留指定的元素(例如通过反转结果)。我想这可以通过基于整数的子集来完成,但无论哪种方式都无关紧要。
与R中的向量子集一样,所有负指数的向量意味着删除相应的元素;而所有正指数的向量表示要保留的元素。我没有检查混合情况,这可能会抛出异常,就像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
*/
答案 1 :(得分:0)
这是我写的一个执行此任务的函数。不使用负指数,而是通过函数调用。它比我的基准测试中的R函数(小向量)慢一点。也许有人可以在它上面构建,我没有测试过nrussel的代码,所以这可能是劣等的。编辑 - 如果你传递包含删除索引的R向量,则将if语句从“inds(j)== i”更改为“inds(j)-1 == i”(我相信)。
注意 - 可以通过根据找到的索引在内循环上设置下限来提高性能。当然假设索引向量按升序排序。
arma::uvec rmIndices( unsigned int vecsize, arma::uvec inds){
unsigned int negInds = 0, p = inds.size();
bool foundMatch = false;
arma::uvec neg_inds(vecsize - p);
for(unsigned int i = 0; i < vecsize; ++i){
for(unsigned int j = 0; j < p; ++j){
if(inds(j) == i){//Check if we have a match between the index and the specified value
foundMatch = true;
}
}//End inner loop
if(!foundMatch){
neg_inds(negInds) = i;
negInds = negInds + 1;//We have a match so, go to next position.
}
foundMatch = false;
}
return( neg_inds );
}