Suponha que eu tenha a seguinte estrutura de dados:
library(dplyr)
d <- tibble(x = paste0("x", 1:3),
op = c("f", "g", "h"),
y = paste0("y", 1:3),
res = paste0("z", 1:3))
Quero criar uma nova coluna cmd
que contenha uma chamada não avaliada que deve ficar assim:
(D <- d %>%
mutate(cmd = list(quote(z1 <- f(x1, y1)),
quote(z2 <- g(x2, y2)),
quote(z3 <- h(x3, y3)))))
# # A tibble: 3 × 5
# x op y res cmd
# <chr> <chr> <chr> <chr> <list>
# 1 x1 f y1 z1 <language>
# 2 x2 g y2 z2 <language>
# 3 x3 h y3 z3 <language>
mas é claro que não quero codificar essas linhas, mas queria extrair esses valores das linhas correspondentes de d
, mas não tive sucesso:
d %>%
rowwise() %>%
mutate(cmd = list(expr(!!sym(res) <- !!sym(op)(!!sym(x), !!sym(y)))))
resulta em:
Error: object 'res' not found
Como eu alcançaria o objetivo?
O NB cmd
será finalmente avaliado em um ambiente onde os argumentos e as funções são definidos, então conceitualmente algo como:
e <- list2env(list(x1 = 1, x2 = 2, x3 = 3, y1 = 2, y2 = 2, y3 = 3,
f = \(x, y) x + y, g = \(x, y) x - y, h = \(x, y) x * y))
eval(D$cmd[[1]], e)
e$z1
# [1] 3
Uma possibilidade seria recorrer ao substituto:
Mas ainda estou procurando uma solução tidyverse.
em Base R você poderia fazer:
Isto é muito longo para um comentário, portanto, postando como uma resposta. Pode ser útil para pessoas que estão encontrando esta pergunta.
Acho que você tem um problema de design. O conselho padrão parece se aplicar: não crie variáveis numeradas em um ambiente. Use vetores e listas.
Este é apenas um exemplo de uso. Você pode, é claro, subconjuntor os vetores/listas de acordo com meta-informações como em seu
d
. O ponto é que você não precisa construir chamadas (e certamente não chamadas para<-
) e avaliá-las como você propõe.Você tem boas respostas básicas de R, então vou focar em
tidyverse
, que parece mudar muito. Esta pergunta de 2017 está relacionada a parte da sua pergunta (construindo uma chamada de atribuição), mas a resposta aceita sugere usarrlang::lang()
, que agora está obsoleto em favor derlang::call2()
. Então, acho que atidyverse
abordagem recomendada agora seria esta:O que lhe dá uma
cmd
coluna parecida com esta:Que avalia como desejado no ambiente da sua pergunta:
E também podemos ver que isso atribui às variáveis desejadas em
e
:Como as colunas de entrada são todas strings, parece fazer sentido usar a manipulação de strings primeiro e então converter para expressões R no final. Nesse caso,
glue
pode ser usado como mostrado:Atualizar
Usei
parse_exprs
no lugar deparse_expr
como sugerido por @SamR eliminandorowwise
.