Rcpp内存管理

时间:2017-02-09 20:36:29

标签: r rcpp

我正在尝试将某些字符数据转换为数字,如下所示。数据将带有特殊的字符,所以我必须把它们拿出来。我将数据转换为std:string以搜索特殊字符。它会在内存中创建一个新变量吗?我想知道是否有更好的方法来做到这一点。

NumericVector converter_ra_(Rcpp::RObject x){
  if(x.sexp_type() == STRSXP){
    CharacterVector y(x);
    NumericVector resultado(y.size());
    for(unsigned int i = 0; i < y.size(); i++){
      std::string ra_string = Rcpp::as<std::string>(y[i]);
      //std::cout << ra_string << std::endl;
      double t = 0;
      int base = 0;
      for(int j = (int)ra_string.size(); j >= 0; j--){
        if(ra_string[j] >= 48 && ra_string[j] <= 57){
          t += ((ra_string[j] - '0') * base_m[base]);
          base++;
        }
      }
      //std::cout << t << std::endl;
      resultado[i] = t;
    }
    return resultado;
  }else if(x.sexp_type() == REALSXP){
    return NumericVector(x);
  }
  return NumericVector();
}

1 个答案:

答案 0 :(得分:4)

  

它是否在内存中创建了一个新变量?

如果输入对象实际上是一个数字向量(REALSXP)并且您只是返回,例如as<NumericVector>(input),然后不会创建其他变量。在任何其他情况下,当然需要为返回的对象分配新的内存。例如,

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector demo(RObject x) {
    if (x.sexp_type() == REALSXP) {
        return as<NumericVector>(x);
    }

    return NumericVector::create();
}

/*** R

y <- rnorm(3)
z <- letters[1:3]

data.table::address(y)
# [1] "0x6828398"

data.table::address(demo(y))
# [1] "0x6828398"

data.table::address(z)
# [1] "0x68286f8"

data.table::address(demo(z))
# [1] "0x5c7eea0"

*/
  

我想知道是否有更好的方法来做到这一点。

首先,您需要定义&#34;更好&#34;:

  • 更快?
  • 使用更少的内存?
  • 更少的代码行?
  • 更像惯用语?

就个人而言,我会从最后一个定义开始,因为它通常需要一个或多个其他定义。例如,在这种方法中我们

  • 定义一个依赖于标准库函数Predicate而不是尝试在本地实现的函数对象isdigit
  • 定义另一个使用erase-remove idiom的函数对象来消除由Predicate确定的字符;如果有必要,使用std::atoi将剩余的内容转换为double(再次,而不是尝试自己实现)
  • 使用Rcpp惯用法 - as转换器 - 将STRSXP转换为std::vector<std::string>
  • 调用std::transform将其转换为结果向量
#include <Rcpp.h>
using namespace Rcpp;

struct Predicate {
    bool operator()(char c) const
    { return !(c == '.' || std::isdigit(c)); }
};

struct Converter {
    double operator()(std::string s) const {
        s.erase(
            std::remove_if(s.begin(), s.end(), Predicate()),
            s.end()
        );

        return s.empty() ? NA_REAL : std::atof(s.c_str());
    }
};

// [[Rcpp::export]]
NumericVector convert(RObject obj) {
    if (obj.sexp_type() == REALSXP) {
        return as<NumericVector>(obj);
    }
    if (obj.sexp_type() != STRSXP) {
        return NumericVector::create();
    }

    std::vector<std::string> x = as<std::vector<std::string> >(obj);
    NumericVector res(x.size(), NA_REAL);

    std::transform(x.begin(), x.end(), res.begin(), Converter());
    return res;
}

测试此功能以实现最低限度的功能,

x <- c("123 4", "abc 1567.35 def", "abcdef", "")
convert(x)
# [1] 1234.00 1567.35      NA      NA

(y <- rnorm(3))
# [1]  1.04201552 -0.08965042 -0.88236960

convert(y)
# [1]  1.04201552 -0.08965042 -0.88236960

convert(list())
# numeric(0)

这是否与经验丰富的C或C ++程序员手写的一样高效?几乎肯定不是。但是,由于我们使用了库函数和常用习语,因此它相当简洁,可能没有错误,而且即使在快速浏览的情况下,其意图也相当明显。如果您需要更快的东西,那么可能会进行一些优化,但如果没有首先进行基准测试和分析,就不需要在该前提下开始。