Rcpp / RcppArmadillo:根据位置从矢量中移除非连续元素

时间:2015-12-31 18:35:28

标签: r vector rcpp

我们说我有一个向量[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可能非常大。

编辑:当我使用两者时,Rcpp或Armadillo的实施都没问题。

2 个答案:

答案 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 );
}