`rlang::eval_tidy()` to evaluate a combination of unquoted and quoted expressions

Currently reading 20 Evaluation | Advanced R. I've been playing a bit with the select2() example that somewhat emulates dplyr::select().

I've an issue when using quoted variables. As you can see in case 1 in the example below, eval_tidy() tends to read quoted variables "as is" which will then convert the entire output to a character vector, breaking the function. What would be a simple work around to make that function work in case 1?

The idea is to make a similar function that works on rows (instead of columns) so things like tidyselect::vars_select() are not what I'm looking for.

library(rlang)

select2 <- function(data, ...) {
  dots <- enquos(...)
  vars <- as.list(set_names(seq_along(data), names(data)))
  idx <- unlist(purrr::map(dots, \(x) eval_tidy(x, vars)))
  print(idx)
  data[, idx, drop = FALSE]
}

tbl <- tibble::tibble(!!!set_names(1:5, c("a", "b", "c", "e", "f g")))
tbl
#> # A tibble: 1 × 5
#>       a     b     c     e `f g`
#>   <int> <int> <int> <int> <int>
#> 1     1     2     3     4     5

# case 1

select2(tbl, a:c, "f g")
#>                         
#>   "1"   "2"   "3" "f g"
#> Error in `data[, idx, drop = FALSE]`:
#> ! Can't subset columns that don't exist.
#> ✖ Columns `1`, `2`, and `3` don't exist.

# case 2

select2(tbl, a:c, `f g`)
#>         
#> 1 2 3 5
#> # A tibble: 1 × 4
#>       a     b     c `f g`
#>   <int> <int> <int> <int>
#> 1     1     2     3     5

Created on 2023-11-27 by the reprex package (v2.0.1)

I guess this is why it's call NSE

library(rlang)
select2 <- function(data, ...) {
  dots <- enquos(...)
  vars <- as.list(set_names(seq_along(data), names(data)))
  idx <- unlist(purrr::map(dots, \(x) eval_tidy(x, vars)))
  print(idx)
  data[, idx, drop = FALSE]
  return(data)
}

tbl <- tibble::tibble(!!!set_names(1:5, c("a", "b", "c", "e", "f g")))

select2(tbl,c( a:c, `f g`))
#>         
#> 1 2 3 5
#> # A tibble: 1 × 5
#>       a     b     c     e `f g`
#>   <int> <int> <int> <int> <int>
#> 1     1     2     3     4     5
select2(tbl, a:c)
#>       
#> 1 2 3
#> # A tibble: 1 × 5
#>       a     b     c     e `f g`
#>   <int> <int> <int> <int> <int>
#> 1     1     2     3     4     5
select2(tbl, `f g`)
#>   
#> 5
#> # A tibble: 1 × 5
#>       a     b     c     e `f g`
#>   <int> <int> <int> <int> <int>
#> 1     1     2     3     4     5
select2(tbl)
#> NULL
#> # A tibble: 1 × 5
#>       a     b     c     e `f g`
#>   <int> <int> <int> <int> <int>
#> 1     1     2     3     4     5

Created on 2023-11-27 with reprex v2.0.2

tidyselect::eval_select(expr(c(...)), vars) was what I was looking for.

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.