评估作为参数传递的列表内的表达式

时间:2018-05-02 13:38:13

标签: r dplyr tidyverse rlang

假设我想从涉及另一个表的列的表达式创建一个新表。这很简单:

library(rlang)
library(purrr)

from_exprs = function(tb, ...) {
  quos(...) %>% 
    map_dfc(~ eval_tidy(., tb)) 
}

示例:

> tb = data.frame(year = 2001:2005, month = 1, names = letters[1:5])
> tb
  year month names
1 2001     1     a
2 2002     1     b
3 2003     1     c
4 2004     1     d
5 2005     1     e
> from_exprs(tb, year + month, toupper(names))
# A tibble: 5 x 2
     V1 V2   
  <dbl> <chr>
1  2002 A    
2  2003 B    
3  2004 C    
4  2005 D    
5  2006 E  

现在我需要评估不是来自...而是来自列表的表达式。我想要一个新函数from_exprs2(),以便像

这样的调用
from_exprs2(tb, 
  Y = list(year + month, year - month), 
  Z = list(toupper(names), tolower(names))
)

返回两个表,每个表对应一个表。以前的策略不起作用:

> from_exprs2 = function(tb, Y, Z) {
+     tb_y = quos(Y) %>% 
+         map_dfc(~ eval_tidy(., tb)) 
+     tb_z = quos(Z) %>% 
+         map_dfc(~ eval_tidy(., tb))
+     list(tb_y, tb_z)
+ }
> from_exprs(tb, Y = list(year + month, year - month), Z = list(toupper(names), tolower(names)))
 Show Traceback

 Rerun with Debug
 Error in cbind_all(x) : Not compatible with STRSXP: [type=NULL]. 

1 个答案:

答案 0 :(得分:1)

比我想象的要容易。使用enquo()捕获表达式,使用eval_tidy()作为列表进行评估。之后,只需将其转换为数据框。

from_exprs2 = function(tb, Y, Z) {
    tb_y = enquo(Y) %>%
        eval_tidy(tb) %>%
        as.data.frame

    tb_z = enquo(Z) %>%
        eval_tidy(tb) %>%
        as.data.frame

    list(tb_y, tb_z)
}

from_exprs2(tb, 
            Y = list(year + month, year - month), 
            Z = list(toupper(names), tolower(names)))

输出:

[[1]]
  c.2002..2003..2004..2005..2006. c.2000..2001..2002..2003..2004.
1                            2002                            2000
2                            2003                            2001
3                            2004                            2002
4                            2005                            2003
5                            2006                            2004

[[2]]
  c..A....B....C....D....E.. c..a....b....c....d....e..
1                          A                          a
2                          B                          b
3                          C                          c
4                          D                          d
5                          E                          e