rfunctionargumentsvary

Is there a way to vary the needed function input?


I have the following function:

my_fct <- 
  function(input1, input2, input3) {
    output <- df %>%
  filter(x = input1 | x = input2 | x = input3
  )
  }

with let's say input1 = c(1:10), input2 = c(1:10), input3 = c(1:10)

In some occassions, I only need one or two of the three inputs, like

output <- my_fct(3, 5)

Unfortunately, my approach requires to insert exactly three arguments. Is there a way to create a function, in which the argument input can vary?

I really appreciate your help, thanks


Solution

  • I'm going to demonstrate using this dataset:

    DAT <- head(mtcars)
    names(DAT)[2] <- "x"
    
    1. Do you mean filter(x == input1 | ...)? x=input1 is unlikely to work as I'm inferring.

    2. Functions should not be breaking scope to assume that an object is visible in the calling environment (df here). Doing it this way breaks reproducibility and can make troubleshooting more difficult. In this case, it can be more difficult since if df does not exist, the error will likely reference function or closure and not just say object 'df' not found`, which can be confusing if you aren't familiar with what's going on.

      For the examples below, I'll explicitly add .data as the first argument to work around this. (Making it the first argument means it'll play nicely with dplyr.) Similarly, I'll guard against "x" not being found in the data ... it might be useful to read https://dplyr.tidyverse.org/articles/programming.html for this, though a bit more work and out of scope for this answer.

    3. We can use default values of NULL, perhaps

      my_fct <- function(.data, input1 = NULL, input2 = NULL, input3 = NULL) {
        stopifnot("x" %in% names(.data))
        .data %>%
          filter(
            if (is.null(input1)) FALSE else x == input1 |
            if (is.null(input2)) FALSE else x == input2 |
            if (is.null(input3)) FALSE else x == input3
          )
      }
      my_fct(DAT)
      #  [1] mpg  x    disp hp   drat wt   qsec vs   am   gear carb
      # <0 rows> (or 0-length row.names)
      my_fct(DAT, 4)
      #             mpg x disp hp drat   wt  qsec vs am gear carb
      # Datsun 710 22.8 4  108 93 3.85 2.32 18.61  1  1    4    1
      my_fct(DAT, 4, 8)
      #                    mpg x disp  hp drat   wt  qsec vs am gear carb
      # Datsun 710        22.8 4  108  93 3.85 2.32 18.61  1  1    4    1
      # Hornet Sportabout 18.7 8  360 175 3.15 3.44 17.02  0  0    3    2
      

      (We can't use is.null(input1) | x == input1 since both sides of | are always run, and x == NULL returns a 0-length vector instead of what we need.)

    4. If input* are always going to be length-1 vectors, we can simplify it a little with

      my_fct <- function(.data, input1 = NULL, input2 = NULL, input3 = NULL) {
        stopifnot("x" %in% names(.data))
        .data %>%
          filter(x %in% c(input1, input2, input3))
      }
      my_fct(DAT)
      #  [1] mpg  x    disp hp   drat wt   qsec vs   am   gear carb
      # <0 rows> (or 0-length row.names)
      my_fct(DAT, 4)
      #             mpg x disp hp drat   wt  qsec vs am gear carb
      # Datsun 710 22.8 4  108 93 3.85 2.32 18.61  1  1    4    1
      my_fct(DAT, 4, 8)
      #                    mpg x disp  hp drat   wt  qsec vs am gear carb
      # Datsun 710        22.8 4  108  93 3.85 2.32 18.61  1  1    4    1
      # Hornet Sportabout 18.7 8  360 175 3.15 3.44 17.02  0  0    3    2
      
    5. If you are looking for something a bit more flexible (such as someday wanting input4 as well, then perhaps

      my_fct <- function(.data, ...) {
        stopifnot("x" %in% names(.data))
        dots <- list(...)
        if (!length(dots)) return(.data[0,])
        .data[rowSums(sapply(dots, function(z) .data$x == z)) > 0,]
      }
      my_fct(DAT)
      #  [1] mpg  x    disp hp   drat wt   qsec vs   am   gear carb
      # <0 rows> (or 0-length row.names)
      my_fct(DAT, 4)
      #             mpg x disp hp drat   wt  qsec vs am gear carb
      # Datsun 710 22.8 4  108 93 3.85 2.32 18.61  1  1    4    1
      my_fct(DAT, 4, 8)
      #                    mpg x disp  hp drat   wt  qsec vs am gear carb
      # Datsun 710        22.8 4  108  93 3.85 2.32 18.61  1  1    4    1
      # Hornet Sportabout 18.7 8  360 175 3.15 3.44 17.02  0  0    3    2
      my_fct(DAT, 4, 11, 29, 394, 8)
      #                    mpg x disp  hp drat   wt  qsec vs am gear carb
      # Datsun 710        22.8 4  108  93 3.85 2.32 18.61  1  1    4    1
      # Hornet Sportabout 18.7 8  360 175 3.15 3.44 17.02  0  0    3    2