Search code examples
rfunctionif-statementdplyrnse

How to use dplyr NSE inside an if condition inside a function?


I have a function which takes an NSE argument.

Let's say I have a tibble with a column that needs ordering. I want to create a function that can order the name of the column based on the name inputted in the function argument. However I want it to not order the column if I don't use the argument, hence I use column_name = NULL as a default argument (or column_name = NA)

sort_tibble <- function(column_name = NULL) {
  tibble_data <- tibble::tibble(NSE_name = c(0.2, -0.4, 1.7, 0.09, -0.6, -1))
  if (!is.null(({{ column_name }}))) {
    tibble_data <- tibble_data %>% arrange({{ column_name }})

    # Do stuff
  }
}

sort_tibble(NSE_name)
#> Error in sort_tibble(NSE_name): objet 'NSE_name' not found

Created on 2022-04-11 by the reprex package (v2.0.1)

However despite how many combinations of quote, {{var}} or rlang::eval_tidy, I can't find an idea to make R understand that column_name is not empty (thus used). It can't find it because it's not a variable but a tidy evaluation, except it's not used in a tidy function.


Solution

  • I finally found a solution !

    The idea here is not to directly try to inject the data for dplyr using {{var}} but to first use a string as function argument input, and to allow it to be evaluated through dplyr using sym() and !!. This allows other non tidy operations to work in the function, including subsetting a data frame or just evaluating whether or not the argument is empty or not (which is my condition for my if function).

    I referred to https://tidyeval.tidyverse.org/sec-why-how.html#unquoting-code

    Using sym() turns the string into a symbol. Symbols are required to be evaluated as a column in dplyr

    sym("NSE_name")
    # NSE_name
    
    

    Then use !! to inject the evaluation into the code

    library(tidyverse)
    f1 <- function(order = NULL) {
      df <-
        tibble::tibble(NSE_name = c(0.2, -0.4, 1.7, 0.09, -0.6, -1))
      f2(order = order)
    }
    
    f2 <- function(order = NULL) {
      if (!is.null(order)) {
        
        ordered_df <- df %>% arrange(!!sym(order))
        return(ordered_df)
      }
      else print ("No order")
    }
    
    f1(order = "NSE_name")
    f1()