Getting unquoted variable names from a vector using rlang

enquo
error: quosures can only be unquoted within a quasiquotation context.
programming with dplyr
r unquote
tidyeval
can only be used within a quasiquoted argument
tidyeval mutate
could not find function "uq"

I am building a function for which I'd like the user to be able to pass unquoted variables. Later on I'm going to need the names of those variables as strings as I prepare the output.

This is no problem if each argument carries only one variable. I can use deparse(substitute(x)) or rlang::as_name(rlang::enquo(x)) to get the name out (with the latter probably being the better approach). But how do I do this if I have them passing in multiple variables in one argument using c()?

The only way I've figured out how to do it so far, after reading a whole bunch about quosures, etc., is names(dplyr::select(data,{{x}})) but I can't imagine that's the proper way to do this.

nameprinter <- function(x, manynames, onename) {
  manynames <- names(dplyr::select(x, {{manynames}}))
  onename <- rlang::as_name(rlang::enquo(onename))

  c(manynames,onename)
}

df <- data.frame(a=1:10,b=1:10,c=1:10)

nameprinter(df,c(a,b),c)
# [1] "a" "b" "c"

What's a better approach to getting the names of the variables passed in manynames than I have here? Thank you.


There is actually already a function for it. We can use vars_select

tidyselect::vars_select(names(df), c(a,b), c)
# a   b   c 
#"a" "b" "c" 

tidyselect::vars_select(names(df), a, b)
#  a   b 
# "a" "b" 

19 Quasiquotation, Make sure you've read the metaprogramming overview in Chapter 17 to get a Each rlang function described above has an equivalent in base R. Their to provide bare variable names in , or a character vector of variable names in list : . If the vector is named, the names are used as argument names. Use qq_show() to experiment with quasiquotation or debug the effect of unquoting operators. qq_show() quotes its input, processes unquoted parts, and prints the result with expr_print() .


You could use base R to accomplish this:

nameprinter <- function(x, manynames, onename) {
  manynames <- substitute(manynames)
  names_env <- setNames(as.list(names(x)), names(x))
  manynames_quo <- eval(manynames, names_env)

  onename <- deparse(substitute(onename))

  c(manynames_quo,onename)
}

df <- data.frame(a=1:10,b=1:10,c=1:10)

nameprinter(df,c(a,b),c)
#[1] "a" "b" "c"

This evaluates our manynames vector based on the names of the variables in our df. This should be a fair bit quicker than using select and then pulling out the names.

Force parts of an expression — quasiquotation • rlang, to force early evaluation of part of an expression before it gets fully evaluated. Since the LHS of = is defused, giving the name of a variable results in the In addition the parser now strips one level of parentheses around unquoted expressions. a custom printer) # when we unquote an integer vector: expr( how_many(! vec_names2() returns the repaired names from a vector, even if it is unnamed. See vec_as_names() for details on name repair. vec_names() is a bare-bones version that returns NULL if the vector is unnamed. vec_set_names() sets the names or removes them.


I don't think that you need to work with the rlang::enquo function directly for this problem:

library("dplyr")

nameprinter <- function(x, manynames, onename) {

  select(df, !!manynames) %>% print()
  select(df, !!onename) %>% print()

  c(manynames, onename)
}

df <- tibble(a = 1:10, b = 1:10, c = 1:10)
nameprinter(df, c("a", "b"), "c")

Is this what you wanted?

quasiquotation function, It gets evaluated immediately in the surrounding context. If the vector is named, the names are used as argument names. Use qq_show() quotes its input, processes unquoted parts, and prints the result with expr_print() . Calling UQ() and UQS() with the rlang namespace qualifier is soft-deprecated as of rlang 0.2.0 . What I want to do (and I think it is an important use case) is take the name of a column as a string from some external source (say from colnames(), or from the yarn-control block of an R-markdown document) and then use that string as a variable name.


I tought of an approach that is more generic and does not depend on a data frame. It uses as_name and applies it to the quosures using vapply...

foo <- function(.data, value_col, ...) {
  group_cols <- enquos(...)
  value_col <- enquo(value_col)
  # do stuff
  .data %>% group_by(!!!group_cols) %>% summarize_at(vars(!!value_col), mean) %>% print()
  # passed columns as a character vector
  vapply(c(group_cols, value_col), rlang::as_name, "")
}
foo(mtcars, mpg, cyl, vs)

Programming with dplyr • dplyr, In most (but not all) base R functions you need to refer to variables with $ , leading i.e. when you want to get the data-variable from an env-variable instead of by using .data$var and importing .data from its source in the rlang package (the If you have a character vector of variable names, and want to operate on them� Note the use of ensym(): we want the user to supply the name of a single variable, not a more complex expression. 19.7.3 Slicing an array An occasionally useful tool missing from base R is the ability to extract a slice of an array given a dimension and an index.


8 dplyr, The primary goal of this book is to get you up to speed with tidy evaluation and how to In tidy eval function it is possible to unquote argument names with !! 3.2 The names attribute of an object. Here we address how to manage the names attribute of an object. Our initial thinking was motivated by how to handle the column or variable names of a tibble, but is evolving into a name-handling strategy for vectors, in general.


r-lib/rlang, I have skimmed the dplyr/tidyeval/rlang documentation and tutorials and I literal values (i.e. vectors) just like you can unquote expressions (though in to get a code-generated string (in a Shiny app) to be a column name� foo <- function(x, args) { args_call <- rlang::enexpr(args) list_of_args <- rlang::lang_args(args_call) mutate(x, !!! list_of_args) } From what I can tell, args is not technically a list yet, it's a promise that will create a list, but once you use lapply() (or any function that forces the evaluation of the promise) on that promise directly you


Add value labels to variables — set_labels • sjlabelled, For set_labels() , Optional, unquoted names of variables that should be selected for set_label to manually set variable labels or get_label to get variable labels; force using all labels, even if not all labels # have associated values in vector x using quasi-quotation library(rlang) library(dplyr) x1 <- "dummy1" x2 <- c("so� So I tried to explicitly specify the joining variables and tried using rlang::as_string, rlang::quo_name, etc., but couldn't get it to work. How can I make this work?