Search code examples
rdplyrevaluationtidyselect

Evaluation with dplyr::select does not work in my function


I am really new on dealing with evaluation issues in R.

example<- data.frame(id = 1:5,
                 pairs0 = c(1, 1, 1, 2, 2),
                 pairs1 = c(2, 2, 1, 1, 1)
                     )

Here is the function that I am trying to write:

f <- function(df, col_pair){
       
       df2 <- df %>% mutate(j = row_number())

full_join(df2 %>% select(j, col_pair),
          df2 %>% select(j, col_pair),
          suffix = c('1', '2'),
          by = "{{col_pair}}",
          keep = TRUE) %>%
filter(j1 != j2)
}

The function picks a data frame df and joins it to itself by column col_pair. The thing is, if I run f(example, pairs0), I get that "join columns must be present in data"

Can someone help?


Solution

  • I have made a modification to your function, you can see as an option because it uses the variable with quotes and it can be less troublesome as using other evaluation schemes. Here the code:

    #Function
    f <- function(df, col_pair){
      
      df2 <- df %>% mutate(j = row_number())
      
      full_join(df2 %>% select(j, col_pair),
                df2 %>% select(j, col_pair),
                suffix = c('1', '2'),
                by = col_pair,
                keep = TRUE) %>%
        filter(j1 != j2)
    }
    #Apply
    f(example, 'pairs0')
    

    Output:

      j1 pairs01 j2 pairs02
    1  1       1  2       1
    2  1       1  3       1
    3  2       1  1       1
    4  2       1  3       1
    5  3       1  1       1
    6  3       1  2       1
    7  4       2  5       2
    8  5       2  4       2
    

    Also, if non standard evaluation is needed you can use this:

    #Option 2
    f <- function(df, col_pair){
      
      var <- enquo(col_pair)
      
      df2 <- df %>% mutate(j = row_number())
      
      full_join(df2 %>% select(j, !!var),
                df2 %>% select(j, !!var),
                suffix = c('1', '2'),
                by = rlang::as_name(var),
                keep = TRUE) %>%
        filter(j1 != j2)
    }
    

    We apply:

    #Apply
    f(example, pairs0)
    

    Output:

      j1 pairs01 j2 pairs02
    1  1       1  2       1
    2  1       1  3       1
    3  2       1  1       1
    4  2       1  3       1
    5  3       1  1       1
    6  3       1  2       1
    7  4       2  5       2
    8  5       2  4       2