I want to build a custom function which returns a date x years ago, or in the case the x supplied is infinite, reverts to a special date. I'm using dplyr
and lubridate
. Here is a trivial example:
foo <- function(years_ago) {
case_when(
years_ago == Inf ~ as.Date("1800-01-01")
TRUE ~ Sys.Date() - years(years_ago)
)
}
foo(1)
duly returns the date 1 year ago. However, foo(Inf)
gives me the error:
argument is not interpretable as logical
. It seems that R jumps to evaluate the TRUE line of the case_when statement, even when the first condition is met.
Is there any way I can get these tidyverse functions to play nicely, or do I need to find a workaround in base R?
CodePudding user response:
It's not a pretty solution, but I think this works? Not sure why testing for Inf
with is.infinite
within the case_when
also fails though as that was my first thought.
foo <- function(years_ago) {
if (is.infinite(years_ago)) {
years_ago <- NA
}
case_when(
is.finite(years_ago) ~ Sys.Date() - years(years_ago),
is.na(years_ago) ~ as.Date("1800-01-01"),
)
}
Alternatively, given the above already carries out the logical statement as part of the "if", then the following should also work?
foo <- function(years_ago) {
if (is.infinite(years_ago)) {
rtrn <- as.Date("1800-01-01")
} else {
rtrn <- Sys.Date() - years(years_ago)
}
rtrn
}
CodePudding user response:
case_when
always evaluates both conditions. So while it would be intuitive to assume that if your value is Inf
, the case when would not evaluate the second line, it actually does. And then the problem is that the years
function can't handle infinite values.
What you could do in the case_when, is to simply add an ifelse command that makes sure the years function is only run on values that are not infinite.
foo <- function(years_ago) {
case_when(
years_ago == Inf ~ as.Date("1800-01-01"),
TRUE ~ Sys.Date() - ifelse(is.infinite(years_ago), years(0), years(years_ago))
)
}
Some examples:
foo(1)
[1] "2022-06-24"
foo(Inf)
[1] "1800-01-01"
foo(0)
[1] "2022-06-24"