Search code examples
rfunctiondplyrpipeellipsis

variable not found when using ellipsis (dotdotdot) inside function with dplyr::if_else


I have a function with ellipsis (dotdotdot) in R, which is parsed into dplyr::if_else as you can see in the example below. However, the error tells me that the variable is not found when it is indeed in the dataframe. My question is simple, how can I parse the ellipsis of a function into an if_else condition inside a pipe? I also tried the !!! alternative by replacing the ... with a proper argument name, but it did not work either

I apologize if this is a duplicate question but I did not find a clear answer somewhere else.

Thank you so much, Best,


library(tidyverse)
#> Warning: package 'tibble' was built under R version 4.0.3
data("mtcars")

myfilter <- function(df, ...) {
  
  if (...length() != 0) {
    df <- df %>% 
      mutate(
        level = if_else(..., "high", "low")
      )
    
  } else{
    df <- df %>% 
      mutate(
        level = "high"
      )
  }
  
  return(df)
  
}

# WORKS
df <- myfilter(mtcars)
"level"  %in%  names(df)
#> [1] TRUE

# DOES NOT WORK
df <- myfilter(mtcars, drat > 3)
#> Error: Problem with `mutate()` input `level`.
#> x object 'drat' not found
#> i Input `level` is `if_else(..., "high", "low")`.



myfilter2 <- function(df, condi = NULL) {
  
  if (!(is.null(condi))) {
    df <- df %>% 
      mutate(
        level = if_else(!!!condi, "high", "low")
      )
    
  } else{
    df <- df %>% 
      mutate(
        level = "high"
      )
  }
  
  return(df)
  
}

# WORKS
df <- myfilter2(mtcars)
"level"  %in%  names(df)
#> [1] TRUE

# DOES NOT WORK
df <- myfilter2(mtcars, drat > 3)
#> Error in myfilter2(mtcars, drat > 3): object 'drat' not found

Created on 2020-10-15 by the reprex package (v0.3.0)


Solution

  • You can use enquos() to capture the values in the dots in quosures that you can expand with !!!. This will work for both cases.

    
    myfilter <- function(df, ...) {
      dots <- rlang::enquos(...)
      print(dots)
      if (length(dots) != 0) {
        df <- df %>% 
          mutate(
            level = if_else(!!!dots, "high", "low")
          )
        
      } else{
        df <- df %>% 
          mutate(
            level = "high"
          )
      }
      
      return(df)
    }
    myfilter(mtcars)
    myfilter(mtcars, drat > 3)
    

    You can get more info in the section on Dealing with multiple arguments from the Tidy Evaluation guide