NickCHK
NickCHK

Reputation: 1233

Getting unquoted variable names from a vector using rlang

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.

Upvotes: 2

Views: 862

Answers (4)

datenzauber.ai
datenzauber.ai

Reputation: 492

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)

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 388817

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" 

Upvotes: 3

Chris
Chris

Reputation: 3986

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.

Upvotes: 2

charlus
charlus

Reputation: 140

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?

Upvotes: 1

Related Questions