16

Is it possible to return 4 different data frames from one function?

Scenario:

I am trying to read a file, parse it, and return some parts of the file.

My function looks something like this:

parseFile <- function(file){

     carFile <- read.table(file, header=TRUE, sep="\t")

     carNames <- carFile[1,]
     carYear  <- colnames(carFile)

     return(list(carFile,carNames,carYear))
}

I don't want to have to use list(carFile,carNames,carYear). Is there a way return the 3 data frames without returning them in a list first?

Sheila
  • 2,438
  • 7
  • 28
  • 37
  • 1
    Is there a particular reason that you want to avoid a list? – Matthew Lundberg Nov 24 '12 at 05:47
  • 1
    Downvoting as vague and useful. Explain what you are attempting and why a list is not appropriate. – IRTFM Nov 24 '12 at 06:02
  • 1
    I'd like to have three different data frames so I can move forward with additional analysis. If I return as a list, I need to access the list and covert each element in the list to a data frame anyways. I just want to know if this is possible in R. – Sheila Nov 24 '12 at 06:04
  • carFile is already a data frame. You could convert the others to data frames before returning them in the list, if that's what you want. – Matthew Lundberg Nov 24 '12 at 06:20

3 Answers3

25

R does not support multiple return values. You want to do something like:

foo = function(x,y){return(x+y,x-y)}
plus,minus = foo(10,4)

yeah? Well, you can't. You get an error that R cannot return multiple values.

You've already found the solution - put them in a list and then get the data frames from the list. This is efficient - there is no conversion or copying of the data frames from one block of memory to another.

This is also logical, the return from a function should conceptually be a single entity with some meaning that is transferred to whatever function is calling it. This meaning is also better conveyed if you name the returned values of the list.

You could use a technique to create multiple objects in the calling environment, but when you do that, kittens die.

Note in your example carYear isn't a data frame - its a character vector of column names.

Spacedman
  • 92,590
  • 12
  • 140
  • 224
3

There are other ways you could do that, if you really really want, in R.

assign('carFile',carFile,envir=parent.frame())

If you use that, then carFile will be created in the calling environment. As Spacedman indicated you can only return one thing from your function and the clean solution is to go for the list.

In addition, my personal opinion is that if you find yourself in such a situation, where you feel like you need to return multiple dataframes with one function, or do something that no one has ever done before, you should really revisit your approach. In most cases you could find a cleaner solution with an additional function perhaps, or with the recommended (i.e. list).

In other words the

envir=parent.frame()

will do the job, but as SpacedMan mentioned

when you do that, kittens die

Slak
  • 578
  • 10
  • 13
1

The zeallot package does what you need in a similar that Python can unpack variables from a function. Reproducible example below.

parseFile <- function(){

  carMPG <- mtcars$mpg
  carName <- rownames(mtcars)
  carCYL <- mtcars$cyl

  return(list(carMPG,carName,carCYL))
}

library(zeallot)
c(myFile, myName, myYear) %<-% parseFile()
RDavey
  • 1,530
  • 10
  • 27