I am using the function ifelse()
to manipulate a date vector. I expected the result to be of class Date
, and was surprised to get a numeric
vector instead. Here is an example:
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04', '2011-01-05'))
dates <- ifelse(dates == '2011-01-01', dates - 1, dates)
str(dates)
This is especially surprising because performing the operation across the entire vector returns a Date
object.
dates <- as.Date(c('2011-01-01', '2011-01-02', '2011-01-03', '2011-01-04','2011-01-05'))
dates <- dates - 1
str(dates)
Should I be using some other function to operate on Date
vectors? If so, what function? If not, how do I force ifelse
to return a vector of the same type as the input?
The help page for ifelse
indicates that this is a feature, not a bug, but I'm still struggling to find an explanation for what I found to be surprising behavior.
You may use data.table::fifelse
(data.table >= 1.12.3
) or dplyr::if_else
.
data.table::fifelse
Unlike
ifelse
,fifelse
preserves the type and class of the inputs.
library(data.table)
dates <- fifelse(dates == '2011-01-01', dates - 1, dates)
str(dates)
# Date[1:5], format: "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"
dplyr::if_else
From dplyr 0.5.0
release notes:
[
if_else
] have stricter semantics thatifelse()
: thetrue
andfalse
arguments must be the same type. This gives a less surprising return type, and preserves S3 vectors like dates" .
library(dplyr)
dates <- if_else(dates == '2011-01-01', dates - 1, dates)
str(dates)
# Date[1:5], format: "2010-12-31" "2011-01-02" "2011-01-03" "2011-01-04" "2011-01-05"