I have an ifelse condition where I want to return a years
value from package lubridate.
However, it does return 0 inside the ifelse and I have no idea why.
library(lubridate)
years(1)
[1] "1y 0m 0d 0H 0M 0S" # correct
years(2)
[1] "2y 0m 0d 0H 0M 0S" # correct
ifelse(1 == 1, years(1), years(2))
[1] 0 # wrong
Can anyone explain why the ifelse returns 0?
CodePudding user response:
Here is why it happens. This is from the bottom of source code of ifelse
, which will run in your example.
ans <- test
len <- length(ans)
ypos <- which(test)
npos <- which(!test)
if (length(ypos) > 0L)
ans[ypos] <- rep(yes, length.out = len)[ypos]
if (length(npos) > 0L)
ans[npos] <- rep(no, length.out = len)[npos]
ans
The function is modifying the ans
vector by element, not the entire vector itself. So therefore the attributes from yes
and no
are being dropped.
ans <- TRUE
ans[1] <- years(1)
ans
# [1] 0
Below is from the the help file. The "mode of the answer will be coerced from logical" starting with the yes
values first.
mode(years(1))
# [1] "numeric"
Value
A vector of the same length and attributes (including dimensions and "class") as test and data values from the values of yes or no. The mode of the answer will be coerced from logical to accommodate first any values taken from yes and then any values taken from no.
CodePudding user response:
Due to the way it constructs its output, ifelse
strips the attributes from a vector. This is not unique to lubridate::year
. It also happens with, for example, dates and date-times
ifelse(1 == 1, as.Date("2022-06-24"), as.Date("2022-06-25"))
#> [1] 19167
Using dplyr::if_else
avoids this problem:
dplyr::if_else(1 == 1, years(1), years(2))
#> [1] "1y 0m 0d 0H 0M 0S"
And obviously the low-tech fix is to do:
years(ifelse(1 == 1, 1, 2))
#> [1] "1y 0m 0d 0H 0M 0S"