shirewoman2
shirewoman2

Reputation: 1928

Within a function that uses non-standard evaluation, check whether a column exists

I'm attempting to use non-standard evaluation with a function where one set of things happen if one column is present in the supplied data.frame and something else happens if a different column is present. I don't know how to check that condition, though, when the user supplies the column names in the function. Here's an example:

DF1 <- tibble(ColA = 1:4, ColB = 9:12)
DF2 <- tibble(ColA = 1:4, ColC = 5:8)

If columnB existed in all data.frames the user might supply, then this function would work:

myfun1 <- function(DF, columnA, columnB){
      columnA <- enquo(columnA)
      columnB <- enquo(columnB)

      DF %>% mutate(NewColumn = !!columnA * !!columnB)
}

myfun1(DF1, columnA = ColA, columnB = ColB)

And if columnC always existed, then this function would work:

myfun2 <- function(DF, columnA, columnC){
      columnA <- enquo(columnA)
      columnC <- enquo(columnC)

      DF %>% mutate(NewColumn = !!columnA / !!columnC)
}

myfun2(DF2, columnA = ColA, columnC = ColC)

But what I really want is a more flexible function that will check whether columnB is a column in the supplied data.frame, do something if it is, and if it isn't, do something else. Something like this except that I know the if statement is incorrect:

myFlexibleFun <- function(DF, columnA, columnB, columnC){
      columnA <- enquo(columnA)
      columnB <- enquo(columnB)
      columnC <- enquo(columnC)

      if(exists(!!columnB)){          # I know "exists" isn't the correct syntax, but what is?
            DF %>% mutate(NewColumn = !!columnA * !!columnB)
      } else {
            DF %>% mutate(NewColumn = !!columnA / !!columnC)
      }
}

I tried if(quote(columnB) %in% names(DF)) and I tried if(deparse(columnB) %in% names(DF)) and those didn't work.

I'd like it if

myFlexibleFun(DF1, columnA = ColA, columnB = ColB)     

and also

myFlexibleFun(DF2, columnA = ColA, columnC = ColC)

both worked.

Upvotes: 1

Views: 69

Answers (1)

caldwellst
caldwellst

Reputation: 5956

quote() isn't working because you've already converted columnB to be a quosore, so you need to use as_label() instead.

myFlexibleFun <- function(DF, columnA, columnB, columnC){
    columnA <- enquo(columnA)
    columnB <- enquo(columnB)
    columnC <- enquo(columnC)

    if(as_label(columnB) %in% names(DF)){
        DF %>% mutate(NewColumn = !!columnA * !!columnB)
    } else {
        DF %>% mutate(NewColumn = !!columnA / !!columnC)
    }
}

This lets you get what you want:

myFlexibleFun(DF1, columnA = ColA, columnB = ColB)
#> # A tibble: 4 x 3
#>    ColA  ColB NewColumn
#>   <int> <int>     <int>
#> 1     1     9         9
#> 2     2    10        20
#> 3     3    11        33
#> 4     4    12        48
myFlexibleFun(DF2, columnA = ColA, columnC = ColC)
#> # A tibble: 4 x 3
#>    ColA  ColC NewColumn
#>   <int> <int>     <dbl>
#> 1     1     5     0.2  
#> 2     2     6     0.333
#> 3     3     7     0.429
#> 4     4     8     0.5

Upvotes: 2

Related Questions