I'm trying to write a recursive function that builds a nested ifelse
call
. I do realize there are much better approaches than nested ifelse
, e.g., dplyr::case_when
and data.table::fcase
, but I'm trying to learn how to approach such problems with metaprogramming.
The following code builds out the nested ifelse
, but I'm struggling to substitute
data
with the actual supplied value, in this case my_df
.
If I replace quote(data)
with substitute(data)
, it only works for the first ifelse
, but after entering the next iteration, it turns into data
.
I think something like pryr::modify_lang
could solve this after the fact, but I think there's probably a base R solution someone knows.
my_df <- data.frame(group = letters[1:3],
value = 1:3)
build_ifelse <- function(data, by, values, iter=1){
x <- call("ifelse",
call("==",
call("[[", quote(data), by),
values[iter]),
1,
if(iter != length(values)) build_ifelse(data, by, values, iter = iter + 1) else NA)
return(x)
}
build_ifelse(data = my_df, by = "group", values = letters[1:3])
# ifelse(data[["group"]] == "a", 1, ifelse(data[["group"]] == "b",
# 1, ifelse(data[["group"]] == "c", 1, NA)))
Thanks for any input!
Edit:
I found this question/answer: https://stackoverflow.com/a/59242109/9244371
Based on that, I found a solution that seems to work pretty well:
build_ifelse <- function(data, by, values, iter=1){
x <- call("ifelse",
call("==",
call("[[", quote(data), by),
values[iter]),
1,
if(iter != length(values)) build_ifelse(data, by, values, iter = iter + 1) else NA)
x <- do.call(what = "substitute",
args = list(x,
list(data = substitute(data))))
return(x)
}
build_ifelse(data = my_df, by = "group", values = letters[1:3])
# ifelse(my_df[["group"]] == "a", 1, ifelse(my_df[["group"]] ==
# "b", 1, ifelse(my_df[["group"]] == "c", 1, NA)))
eval(build_ifelse(data = my_df, by = "group", values = letters[1:3]))
# [1] 1 1 1