I would like to replace the LHS of "=" in a expression in R. In my personal case, I need it to make sure the following creates a variable that does not already exist in the data frame
df %>% mutate(v = mean(w))
I tried eval(substitute())
but the LHS is not substituted
eval(substitute(df %>% mutate(v = mean(w)), list(v = as.name("id"))))
#similarly in a list
eval(substitute(l <- list(v=1:10),list(v=as.name("id"))))
l
$v
[1] 1 2 3 4 5 6 7 8 9 10
Why can't v
substituted throught eval/substitute? What's the best way to work around it?
1) eval/parse Create a cmd
string, parse it and evaluate it:
f2 <- function(DF, x, env = parent.frame()){
cmd <- sprintf("mutate(%s, %s = mean(v1))", deparse(substitute(DF)), x)
eval(parse(text = cmd), env)
}
f2(DF, "v1_name")
giving
v1 v1_mean
1 1 2
2 2 2
3 3 2
... etc ...
2) eval/as.call Another way is to construct a list, convert it to a call and evaluate it. (This is also the approach that mutate_each_q
in dplyr takes.)
f3 <- function(DF, x, env = parent.frame()) {
L <- list(quote(mutate), .data = substitute(DF), quote(mean(v1)))
names(L)[3] <- x
eval(as.call(L), env)
}
f3(DF, "v1_name")
3) do.call We form a list equal to the last two components of the list in the prior solution and then use do.call
:
f3 <- function(DF, x, env = parent.frame()) {
L <- list(.data = substitute(DF), quote(mean(v1)))
names(L)[2] <- x
do.call(mutate, L)
}
f3(DF, "v1_name")
Upodate Added additional solutions.