Search code examples
rtidyverserlangnon-standard-evaluation

Capturing expressions inside lists as text


I currently have this function, which takes a table and two lists of expressions, and evaluates them, turning them into two matrices. I use two lists instead of ... because I need to be able to determine whether the expressions are going to fall in Y or Z.

func = function(tb, Y, Z) {
  Y_matrix = enquo(Y) %>% 
    eval_tidy(tb) %>%
    as.data.frame %>%
    as.matrix

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

  list(Y_matrix, Z_matrix)
}

For instance:

> tb = data.frame(a = 1:3, b = 3:1, c = 2*(1:3))
> func(tb, list(a + b, a - b), list(a*c, a + b + c))
[[1]]
     c.4L..4L..4L. c..2L..0L..2L.
[1,]             4             -2
[2,]             4              0
[3,]             4              2

[[2]]
     c.2..8..18. c.6..8..10.
[1,]           2           6
[2,]           8           8
[3,]          18          10

However, I also want to capture the expressions inside the lists as text, so I could use them to name the columns. For instance, my desired output would be something like:

> func(tb, list(a + b, a - b), list(a*c, a + b + c))
[[1]]
             a+b            a-b
[1,]             4             -2
[2,]             4              0
[3,]             4              2

[[2]]
              a*c         a + b + c
[1,]           2           6
[2,]           8           8
[3,]          18          10

How can I do this?


Solution

  • You can use something like deparse to go over the language elements in your list to turn those into strings. For example

    func = function(tb, Y, Z) {
      Y_names <- map_chr(as.list(enexpr(Y))[-1], deparse)
      Y_matrix = enquo(Y) %>% 
        eval_tidy(tb) %>%
        as.data.frame %>%
        set_names(Y_names) %>% 
        as.matrix
    
      Z_names <- map_chr(as.list(enexpr(Z))[-1], deparse)
      Z_matrix = enquo(Z) %>%
        eval_tidy(tb) %>%
        as.data.frame %>%
        set_names(Z_names) %>% 
        as.matrix
    
      list(Y_matrix, Z_matrix)
    }
    

    which works with this example

    func(tb, list(a + b, a - b), list(a*c, a + b + c))
    # [[1]]
    #      a + b a - b
    # [1,]     4    -2
    # [2,]     4     0
    # [3,]     4     2
    
    # [[2]]
    #      a * c a + b + c
    # [1,]     2         6
    # [2,]     8         8
    # [3,]    18        10