简体   繁体   English

使用rlang :: env_get在mutate调用的祖父母环境中评估变量

[英]Use rlang::env_get to evaluate a variable in the grandparent environment of the mutate call

I want to use env_get to evaluate a variable in the grandparent environment (I think) of the mutate call, but I couldn't manage. 我想使用env_get在mutate调用的祖父母环境(我认为)中评估变量,但是我无法管理。 I'm describing a minimal example below. 我在下面描述一个最小的例子。

Given a list like the following: 给出如下列表:

library(dplyr)

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

And custom mutate for these lists. 然后为这些列表自定义mutate。

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

I want a function that can be run inside the mutate and can use the value of X . 我想要一个可以在mutate内部运行并可以使用X值的函数。 Something like the following which doesn't work: 像下面这样的东西不起作用:

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

This works as expected. 这按预期工作。

mutate(l, n + 1)

And I would like to be able to do this: 我希望能够做到这一点:

mutate(l, addX(n))

And this doesn't work. 这是行不通的。 I guess I should go up parents somehow and be able to refer to the list, but I couldn't manage. 我想我应该以某种方式上父母,并能够参考这份名单,但我无法解决。 I tried to get the plausible names of the list arguments like this: 我试图得到像这样的列表参数的合理名称:

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

mutate(l, addX_test(n))

But I get stuff like the following: 但是我得到如下内容:

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

Any pointers? 有指针吗? Is it even doable? 甚至可行吗?

Your X is a field inside l , so it's not directly visible in the corresponding environment. 您的Xl内的字段,因此在相应的环境中不直接可见。 If you search for l instead, you can then access its fields. 如果您搜索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
# ...

In general, it's not advisable to traverse the calling stack like that, because it breaks modularity of your code and introduces non-trivial dependencies that could lead to obscure bugs. 通常,不建议像这样遍历调用堆栈,因为它破坏了代码的模块化并引入了非平凡的依赖关系,这些依赖关系可能导致难以理解的错误。 In my opinion, a better approach is to use a function generator (function that returns a function), which will effectively bind the value of X to the computation that uses it: 我认为,更好的方法是使用函数生成器(返回函数的函数),该函数将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

Note that this version is more robust to a name change for your list, because it no longer searches for l directly. 请注意,此版本对于列表的名称更改更可靠,因为它不再直接搜索l

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM