17.5 The list object

Lists and loops go hand in hand. The more you program with R, the more you’ll find yourself using loops.

Let’s say you are conducting a loop where the outcome of each index is a vector. However, the length of each vector could change - one might have a length of 1 and one might have a length of 100. How can you store each of these results in one object? Unfortunately, a vector, matrix or dataframe might not be appropriate because their size is fixed. The solution to this problem is to use a list(). A list is a special object in R that can store virtually anything. You can have a list that contains several vectors, matrices, or dataframes of any size. If you want to get really Inception-y, you can even make lists of lists (of lists of lists….).

To create a list in R, use the list() function. Let’s create a list that contains 3 vectors where each vector is a random sample from a normal distribution. We’ll have the first element have 10 samples, the second will have 5, and the third will have 15.

# Create a list with vectors of different lengths
 number.list <- list(
      "a" = rnorm(n = 10),
      "b" = rnorm(n = 5),
      "c" = rnorm(n = 15))
 
 number.list
## $a
##  [1] -1.24  0.17 -1.19 -0.58 -1.23  0.92  1.62 -2.02 -0.25  0.92
## 
## $b
## [1] -1.627 -1.103 -0.524  0.072 -2.351
## 
## $c
##  [1] -0.6539  0.4062 -0.6126 -0.3552 -1.0043 -0.4276 -2.3236 -0.6905
##  [9] -0.4258 -1.0483  0.7000  0.7408 -0.0878  0.6970 -0.0016

To index an element in a list, use double brackets [[]] or $ if the list has names. For example, to get the first element of a list named number.list, we’d use number.ls[[1]]:

# Give me the first element in number.list
number.list[[1]]
##  [1] -1.24  0.17 -1.19 -0.58 -1.23  0.92  1.62 -2.02 -0.25  0.92

# Give me the element named b
number.list$b
## [1] -1.627 -1.103 -0.524  0.072 -2.351

Ok, now let’s use the list object within a loop. We’ll create a loop that generates 5 different samples from a Normal distribution with mean 0 and standard deviation 1 and saves the results in a list called samples.ls. The first element will have 1 sample, the second element will have 2 samples, etc.

First, we need to set up an empty list container object. To do this, use the vector function:

# Create an empty list with 5 elements
samples.ls <- vector("list", 5)

Now, let’s run the loop. For each run of the loop, we’ll generate i random samples and assign them to the ith element in samples.ls

 for(i in 1:5) {
   samples.ls[[i]] <- rnorm(n = i, mean = 0, sd = 1)
 }

Let’s look at the result:

samples.ls
## [[1]]
## [1] 0.062
## 
## [[2]]
## [1] 0.96 2.06
## 
## [[3]]
## [1]  0.490  0.946 -0.023
## 
## [[4]]
## [1]  1.45  0.28  0.67 -0.97
## 
## [[5]]
## [1]  0.614 -0.098  0.778 -0.209  0.288

Looks like it worked. The first element has one sample, the second element has two samples and so on (you might get different specific values than I did because the samples were drawn randomly!).