Creating a Templated Function to Fill a Vector with another depending on Size

若如初见. 提交于 2019-12-23 04:26:54

问题


Is there a base function in Rcpp that:

  1. Fills entirely by a single value if size of a vector is 1.
  2. Fills the other vector completely if same length.
  3. Fills with an NA value if neither Vector are the same length nor a vector is of size 1.

I've written the above criteria as a function below using a NumericVector as an example. If there isn't a base function in Rcpp that performs said operations there should be a way to template the function so that given any type of vector (e.g. numeric, character and so on) the above logic would be able to be executed.

// [[Rcpp::export]]
NumericVector cppvectorize(NumericVector x,NumericVector y) {

  NumericVector y_out(y.size());

  if(x.size() == 1) {
    for(int i = 0; i < y_out.size(); i++) {
      y_out[i] = x[0];
    }
  } else if(x.size() == y_out.size()) {
    for(int i = 0; i < y_out.size(); i++) {
      y_out[i] = x[i];
    }
  } else {
    for(int i = 0; i < y_out.size(); i++) {
      y_out[i] = NA_REAL;
    }
  }

  return y_out;
} 

回答1:


Unfortunately, the closest you will come to such a function is one of the rep variants that Rcpp supports. However, none of the variants match the desired output. Therefore, the only option is to really implement a templated version of your desired function.

To create the templated function, we will first create a routing function that handles the dispatch of SEXP objects. The rationale behind the routing function is SEXP objects are able to be retrieved from and surfaced into R using Rcpp Attributes whereas a templated version is not. As a result, we need to specify the SEXTYPE (used as RTYPE) dispatches that are possible. The TYPEOF() macro retrieves the coded number. Using a switch statement, we can dispatch this number into the appropriate cases.

After dispatching, we arrive at the templated function. The templated function makes use of the base Vector class of Rcpp to simplify the data flow. From here, the notable novelty will be the use of ::traits::get_na<RTYPE>() to dynamically retrieve the appropriate NA value and fill it.

With the plan in place, let's look at the code:

#include <Rcpp.h>
using namespace Rcpp;

// ---- Templated Function

template <int RTYPE>
Vector<RTYPE> vec_helper(const Vector<RTYPE>& x, const Vector<RTYPE>& y) {
  Vector<RTYPE> y_out(y.size());

  if(x.size() == 1){
    y_out.fill(x[0]);
  } else if (x.size() == y.size()) {
    y_out = x;
  } else {
    y_out.fill(::traits::get_na<RTYPE>());
  }

  return y_out;
} 

// ---- Dispatch function

// [[Rcpp::export]]
SEXP cppvectorize(SEXP x, SEXP y) {
  switch (TYPEOF(x)) {
  case INTSXP: return vec_helper<INTSXP>(x, y);
  case REALSXP: return vec_helper<REALSXP>(x, y);
  case STRSXP: return vec_helper<STRSXP>(x, y);
  default: Rcpp::stop("SEXP Type Not Supported."); 
  }
  // Need to return a value even though this will never be triggered
  // to quiet the compiler.
  return R_NilValue;
}

Sample Tests

Here we conduct a few sample tests on each of the supported data

# Case 1: x == 1

x = 1:5
y = 2

cppvectorize(x, y)
## [1] NA

# Case 2: x == y

x = letters[1:5]
y = letters[6:10]

cppvectorize(x, y)
## [1] "a" "b" "c" "d" "e"

# Case 3: x != y && x > 1

x = 1.5
y = 2.5:6.5

cppvectorize(x, y)

## [1] 1.5 1.5 1.5 1.5 1.5


来源:https://stackoverflow.com/questions/43394389/creating-a-templated-function-to-fill-a-vector-with-another-depending-on-size

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!