【问题标题】:how to iterate inside the elements of a quosure of rlang in R如何在R中的rlang quosure的元素内进行迭代
【发布时间】:2018-10-01 12:01:51
【问题描述】:

假设如果X 出现在quosure 中,我现在想这样做。

library(rlang)
library(purrr)
q <- quo(mean(X))

我知道我可以用 expr 检查是否相等

q[[2]][[2]] == expr(X)
[1] TRUE

但是如何迭代或展平 quo 元素? flatten(q) 不起作用,我不能使用 for 循环,不知道如何使用来自 purrr 的一些 map 函数。

理想情况下,我想在 X 是“数据”而不是任何函数时捕获它。

【问题讨论】:

    标签: r purrr rlang


    【解决方案1】:

    我使用以下自定义函数将表达式转换为它们的Abstract Syntax Trees (ASTs):

    getAST <- function( ee ) { as.list(ee) %>% purrr::map_if(is.call, getAST) }
    

    由于您正在使用 quosures,因此有一个检索相关表达式的中间步骤:

    ## Define a quosure
    ## Side note: don't use q as a variable name; it conflicts with q()
    qsr <- quo( mean(5*X+2) )
    
    ## The associated expression
    xpr <- rlang::get_expr( qsr )
    
    ## ...and its AST
    ast <- getAST( xpr )
    # List of 2
    #  $ : symbol mean
    #  $ :List of 3
    #   ..$ : symbol +
    #   ..$ :List of 3
    #   .. ..$ : symbol *
    #   .. ..$ : num 5
    #   .. ..$ : symbol X
    #   ..$ : num 2
    

    从这里,您可以使用标准技术找到X。例如,展平嵌套列表并将每个元素与expr(X) 进行比较,如您的问题所示:

    purrr::has_element( unlist(ast), expr(X) )
    # [1] TRUE
    
    purrr::map_lgl( unlist(ast), identical, expr(X) )
    # [1] FALSE FALSE FALSE FALSE  TRUE FALSE
    

    【讨论】:

    • 这真是太酷了!我想捕捉的 X 不应该是一个函数,这又如何呢?这意味着 X 将成为最终列表的一部分(内部没有任何列表)并且它不会被 [[1]] 索引,对吗? (如果我是对的,我如何只提取结束列表来做到这一点?)
    • 比这复杂一点。一方面,函数本身可以作为参数传递给其他函数。例如,在summarize_at( mtcars, "wt", sum ) 中,函数sumsummarize_at 的一个参数,并将在AST 中显示为终端叶。其次,比较getAST( expr(X) )getAST( expr(X()) )。它们都产生相同的 AST,因此无法区分 XX()。如果你有兴趣测试某个东西是否是函数,我建议使用内置的is.function()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    • 2016-08-12
    • 2021-07-04
    • 2022-11-15
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    相关资源
    最近更新 更多