How to iterate over an Rcpp DateVector (with example)
In a recent Rcpp project I wanted (in C++) to iterate over the elements of a DateVector
. It turns out that my naive approach didn’t work, and it took me a fair bit of Googling to find the answer so I thought it was worth recording. If you’re in a rush you can skip the preamble and jump straight to the solution.
Iterating over DateVector
s doesn’t work as expected#
For the sake of this example let’s say I was trying to duplicate lubridate::year()
, i.e. given a vector of dates, return a vector containing just the year of those dates. An Rcpp::Date
object has a getYear()
method, but a DateVector
doesn’t have an equivalent. No problem, just loop over the DateVector
and call the getYear()
method on each, right?
Here’s my first attempt:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
IntegerVector get_years(const DateVector& dates) {
auto n = dates.length();
IntegerVector out(n);
for (auto i = 0; i < n; i++) {
out[i] = dates[i].getYear();
}
return out;
}
To my surprise this yielded a compiler error saying that the getYear()
method doesn’t exist for double
objects, which is confusing because I’m working with a vector of Date
s, not double
s, aren’t I?
E> get-years.cpp: In function 'Rcpp::IntegerVector get_years(const DateVector&)':
get-years.cpp:9:23: error: request for member 'getYear' in
[...looooong Rcpp class description...]
which is of non-class type 'const type {aka const double}'
E> out[i] = dates[i].getYear();
E> ^
The solution: create a Date
object#
If we explicitly create a Date
object first the compiler is perfectly happy; the code below works as expected:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
IntegerVector get_years(const DateVector& dates) {
auto n = dates.length();
IntegerVector out(n);
for (auto i = 0; i < n; i++) {
Date d = dates[i];
out[i] = d.getYear();
}
return out;
}
An explanation for this behaviour is given in a related StackOverflow question. To quote duckmayr’s answer:
[…] an
Rcpp::DateVector
is not a vector ofRcpp::Date
s, but is a class derived fromRcpp::NumericVector
(see here). This makes sense considering R’s own internal treatment of date vectors:pryr::sexp_type(as.Date("2019/05/04")) # [1] "REALSXP"
To which Dirk Eddelbuettel, the maintainer of Rcpp, added:
[…] conversion[s] which do require to/from conversion to
SEXP
“generally work” but the compiler sometimes needs some help. As such the assigning of aDateVector
element to aDate
makes comparison easier.
This explains the compiler error, but for me it was not intuitive that a DateVector
is not the same as a vector of Date
s.
duckmeyr’s answer goes on to suggest an alternative:
If what you actually want is a vector of
Rcpp::Date
s, that can be achieved easily as well using the member functiongetDates()
:// [[Rcpp::export]] bool dateProb(DateVector dateVec, Date date) { Date date2 = dateVec(0); std::vector<Date> newdates = dateVec.getDates(); Rcpp::Rcout << (newdates[0] < date) << "\n"; return (date2 < date); }
Hopefully this post was useful to someone, and you found your answer quicker than I did!