Используйте rlang :: env_get для оценки переменной в среде дедушки вызова mutate - PullRequest
0 голосов
/ 05 октября 2018

Я хочу использовать env_get для оценки переменной в среде дедушки (я думаю) вызова mutate, но я не смог справиться.Ниже я описываю минимальный пример.

Учитывая список, подобный следующему:

library(dplyr)

l <- list(X = 10,
        df = tibble(n = seq(-10,10), y = rnorm(21), z = runif(21)))

И пользовательское изменение для этих списков.

mutate_.list <- function(.data, ...){
    mutate_(.data$df, ...)
}

Я хочуфункция, которая может быть запущена внутри mutate и может использовать значение X.Что-то вроде следующего, которое не работает:

addX <- function(x) {
    X <-  rlang::env_get(env = parent.frame(2), 'X', inherit = TRUE)
    x + X
}

Это работает, как и ожидалось.

mutate(l, n + 1)

И я хотел бы иметь возможность сделать это:

mutate(l, addX(n))

И это не работает.Думаю, мне стоит как-то подойти к родителям и иметь возможность обратиться к списку, но я не справился.Я пытался получить правдоподобные имена аргументов списка, как это:

addX_test <- function(x) {
    print(rlang::env_names(parent.frame(1)))  
    x 
}

mutate(l, addX_test(n))

Но я получаю такие вещи, как:

[1] "~"                        ".top_env"                
[3] ".__tidyeval_data_mask__." ".env"

Есть указатели?Это вообще выполнимо?

1 Ответ

0 голосов
/ 09 октября 2018

Ваш X является полем внутри l, поэтому он не виден напрямую в соответствующей среде.Если вы вместо этого выполните поиск l, вы сможете получить доступ к его полям.

addX( 1:3 )   # Error: object 'X' not found

addX_v2 <- function(x) {
  ll <- rlang::env_get(env = parent.frame(2), 'l', inherit = TRUE)
  x + ll$X
}
addX_v2( 1:3 )
# [1] 11 12 13

mutate( l, addX_v2(n) )
# # A tibble: 21 x 4
#        n      y     z `addX_v2(n)`
#    <int>  <dbl> <dbl>        <dbl>
#  1   -10  0.693 0.359            0
#  2    -9 -1.43  0.378            1
#  3    -8 -0.287 0.289            2
#  4    -7 -1.27  0.149            3
# ...

В общем случае нежелательно проходить через такой стек вызовов, поскольку это нарушает модульность вашего кода ивводит нетривиальные зависимости, которые могут привести к неясным ошибкам.На мой взгляд, лучшим подходом является использование генератора функций (функция, которая возвращает функцию), которая будет эффективно связывать значение X с вычислением, которое его использует:

Xadder <- function( .list ) { function(x) {x + .list$X} }

addX_v3 <- Xadder( l )
addX_v3(1:3)
# [1] 11 12 13

mutate( l, addX_v3(n) )     # Works as expected

Обратите внимание, что этоверсия более устойчива к изменению названия вашего списка, потому что больше не ищет l напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...