1

I'm writing a function in R that takes either a data.frame or a file path, leading to a csv that would be read in as a data.frame.

I currently have this:

occInput <- function(fileInput, dfInput = NA) {  
  if (is.na(dfInput)) occ.dat <- read.csv(file = fileInput)
  else occ.dat <- dfInput

  #manipulate the data in occ.dat
}

However, when I actually pass in a data.frame as the dfInput parameter, it throws the warning:

Warning in if (is.na(dfInput)) occ.dat <- read.csv(file = fileInput) else occ.dat <- dfInput: the condition has length > 1 and only the first element will be used

While this does not actually adversely affect my code, it's ugly, and it suggests to me that there is a more elegant way to have either/or optional arguments in a function.

Any suggestions? I feel like I'm overlooking something obvious.

1
  • I think checking for is.null(dfInput) is an better option. Commented May 17, 2018 at 22:03

4 Answers 4

6

You should not trust on NA when argument is expected to get value as data.frame, list etc. is.na returns NA check for each element to those data structures. The better option could be to initialize your argument with NULL and check with is.NULL. Another option could be to use missing function on dfInput argument. Your function definition can be written as:

occInput <- function(fileInput, dfInput = NULL) {  
  if (is.NULL(dfInput)) occ.dat <- read.csv(file = fileInput)
  else occ.dat <- dfInput

  #manipulate the data in occ.dat
}

#OR you can just use missing function

occInput <- function(fileInput, dfInput) {  
  #Perform missing check
  if (missing(dfInput)) occ.dat <- read.csv(file = fileInput)
  else occ.dat <- dfInput

  #manipulate the data in occ.dat
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, missing() is exactly what I needed. Much less hacky than what I was trying to do...
1

Why have two arguments? Just have one and test if its data-framey:

occInput <- function(Input) {  
  if (!inherits(Input,"data.frame")){
    # its not a data frame, so treat as a file name...
    Input = read.csv(Input)
  }
  # Now Input is a data frame...
}

works with data frames, data tables, and tibbles.

Comments

0

I've found one (slightly hacky) way to do it: use if (identical(dfInput, NA)) rather than if (is.na(dfInput)), which does not throw any errors, as it checks whether the two arguments are identical rather than equivalent.

However, it still doesn't seem very elegant to me. I'll leave the question unsolved in case someone else wants to take a better stab at it.

Comments

0

if does only check the first element of a vector otherwise you get mentioned warning.

Checking the class of the passed argument is quite more error tolerant:

occInput <- function(fileInput, dfInput = NA) {  
  if ("data.frame" %in% class(dfInput)) print("dfInput contains a data.frame") # read.csv(file = fileInput)
}

> occInput("adsf")
> occInput("adsf", "asdf")
> occInput("adsf", NULL)
> occInput("adsf", 1:10)
> occInput(dfInput = as.data.frame(mtcars))
[1] "dfInput contains a data.frame"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.