ли она создает новую переменную в памяти?
Если входной объект фактически является числовым вектором (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"
*/
Я хочу знать, если есть лучший способ сделать это.
Прежде всего, необходимо определить "лучше":
- быстрее?
- Использует меньше памяти?
- Меньше строк кода?
- Более идиоматический?
Лично я бы начал с последнего определения, так как он часто влечет за собой один или несколько других. Например, при таком подходе мы
- Определим функцию объекта
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;
}
Testing это для минимальной функциональности,
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++ программист? Почти наверняка нет. Однако, поскольку мы использовали библиотечные функции и общие идиомы, он достаточно краток, скорее всего, будет без ошибок, и намерение довольно очевидно даже при быстром взгляде.Если вам нужно что-то быстрее, то, вероятно, потребуется несколько оптимизаций, но сначала не нужно начинать с этой предпосылки без бенчмаркинга и профилирования.
Сначала добавьте образец данных, используя 'dput (data_set_here)'. Во-вторых, да. Вы собираетесь выделить новый вектор памяти, если тип не является «NumericVector». – coatless