9.4 Returning Multiple Values

Lists combine many different sorts of objects into one object. This makes them very useful in the context of certain functions.

Consider, for example, the drunken-turtle simulation from Section 6.8:

drunkenSim <- function(steps = 1000, reps = 10000, close = 0.5, 
                       seed = NULL, table = FALSE) {
  if ( !is.null(seed) ) {
    set.seed(seed)
  }
  
  returns <- numeric(reps)
  
  for (i in 1:reps) {
  angle <- runif(steps, 0 , 2*pi)
  xSteps <- cos(angle)
  ySteps <- sin(angle)
  
  x <- cumsum(xSteps)
  y <- cumsum(ySteps)
  
  dist <- sqrt(x^2 + y^2)
  closeReturn <- (dist < 0.5)
  returns[i] <- sum(closeReturn)
  }
  
  if ( table ) {
    cat("Here is a table of the number of close returns:\n\n")
    tab <- prop.table(table(returns))
    print(tab)
    cat("\n")
  }
  cat("The average number of close returns was:  ", 
      mean(returns), ".", sep = "")
}

Suppose that we would like to store several of the results of the simulation:

  • the vector of the number of close returns on each repetition;
  • the table made from the close-returns vector;
  • the mean number of returns.

Unfortunately a function can only return one object.

The solution to your problem is to make a list of the three objects we want, and then return the list. We can re-write the function so as to make all output to the console optional. The function will construct the list and return it invisibly.

drunkenSimList <- function(steps = 1000, reps = 10000, close = 0.5, 
                       seed = NULL, verbose = FALSE) {
  if ( !is.null(seed) ) {
    set.seed(seed)
  }
  
  # get the returns:
  returns <- numeric(reps)
  for (i in 1:reps) {
  angle <- runif(steps, 0 , 2*pi)
  xSteps <- cos(angle)
  ySteps <- sin(angle)
  
  x <- cumsum(xSteps)
  y <- cumsum(ySteps)
  
  dist <- sqrt(x^2 + y^2)
  closeReturn <- (dist < 0.5)
  returns[i] <- sum(closeReturn)
  }
  # compute the table and the mean:
  tableReturns <- table(returns)
  meanReturns <- mean(returns)
  
  # handle output to console if user wants it
  if ( verbose ) {
    cat("Here is a table of the number of close returns:\n\n")
    print(prop.table(tableReturns))
    cat("\n")
    cat("The average number of close returns was:  ", 
      meanReturns, ".", sep = "")
  }
  
  # assemble the desired three items into a list
  # (for conveneince, name the items)
  results <- list(tableReturns = tableReturns,
                  meanReturns = meanReturns,
                  returns = returns)
  # return the list
  invisible(results)
}

Now we can run the function simply to acquire the simulation results for later use:

simResults <- drunkenSimList(seed = 3939)

We can use any of the results at any time and in any way we like:

cat("On the first ten repetitions, the number of close returns were:\n\n\t",
    simResults$returns[1:10])
## On the first ten repetitions, the number of close returns were:
## 
##   0 6 4 4 2 0 2 5 2 4