Pass vector of unquoted column names to a function and use first element
Asked Answered
U

2

9

This works as expected:

library(dplyr)

f <- function(x = c(am, vs)) 
  mtcars %>% 
    select({{x}})

How would I rewrite the function (let's call it f2) such that f2 selects only the first element of x, that is f2() should eventually be the same as mtcars %>% select(am)?

Some requirements:

  • I do want to pass the columns as vector, thus a solution using ... would not work in my case.
  • I want to stay inside the tidyverse syntax and want to pass unquoted column names, that is using x = c("am", "vs") is also not desired.
Upswing answered 6/9, 2024 at 11:57 Comment(1)
mtcars %>% select({{x}}) %>% select(1)Kalvn
E
11

tidyselect::eval_select() returns a vector of indices used by select() that can be subset, so one approach might be:

library(tidyselect)
library(dplyr)

f2 <- function(x = c(am, vs)){
  mtcars %>%
    select(first(eval_select(expr({{x}}), data = .)))
}

f2() |>
  names()

[1] "am"
Eyed answered 6/9, 2024 at 13:46 Comment(1)
Ah nice find, exactly what I was looking for, thx.Upswing
C
2

two other approaches:

  1. (deleted)


    f2 <- function(x = c(am, vs)){
      mtcars |> select({{x}}) |> select(1)
    }

Canica answered 6/9, 2024 at 14:15 Comment(2)
Approach (1) is unambiguously bad and should never be used: don’t write brittle, poorly readable ad-hoc parsers for a subset of R. This is a general rule for maintaining code quality but it’s doubly true for R where it’s utterly unnecessary since we have a complete metaprogramming API at our disposal. enquo(x)[[2L]] does the same thing (still not particularly well, but miles better than using regex to parse a non-regular expression).Introrse
took it offlineCanica

© 2022 - 2025 — McMap. All rights reserved.