13.5 Recursive vectors (lists)

  • Lists can contain other lists implying that are more complex than atomic vectors.
    • Hence, suitable to represent hierarchical or tree-like structures.
  • Use list() to create lists.
(xl <- list(1, 2, 3))
  • We use the function str() to assess the structure.
str(xl)
dplyr::glimpse(xl)
#seems one and the same thing?
  • Lists can be named:
xl_named <- list(a = 1, b = 2, c = 3)
str(xl_named)
  • list() can contain a mix of objects unlike atomic vectors.
yl <- list("a", 1L, 1.5, TRUE)
str(yl)
  • Lists can contain other lists!
zl <- list(list(1, 2), list(3, 4))
str(zl)

13.5.1 Visualising lists

  • Let’s see a visual representation of lists. E.g.,
x1 <- list(c(1, 2), c(3, 4))
x2 <- list(list(1, 2), list(3, 4))
x3 <- list(1, list(2, list(3)))

A visual drawing of the lists:

There are three principles:

  1. Lists have rounded corners. Atomic vectors have square corners.

  2. Children are drawn inside their parent, and have a slightly darker background to make it easier to see the hierarchy.

  3. The orientation of the children (i.e. rows or columns) isn’t important, a row or column orientation are picked to either save space or illustrate an important property in the example. ??

13.5.2 Subsetting

  • We can subset lists using three ways, let’s see the example below.
a <- list(a = 1:3, b = "a string", c = pi, d = list(-1, -5))
  1. [ extracts a sub-list. And the result will always be a list.
str(a[1:2])

str(a[4])

We can also subset lists with a logical, integer or character vector as seen in vectors.

  1. [[ extracts a single component from a list. It removes a level of hierarchy from the list.
str(a[[1]])

str(a[[4]])
  1. $ is a shorthand to extract named elements of a list. It works similarly to [[ except that you don’t need to use quotes.
a$a

a[["a"]]
  • Difference between [ and [[ is important for lists:
    • [[ drills down into the list while [ returns a new, smaller list. Let’s compare the code and output above with the visual shown below.

13.5.3 Lists of condiments

  • Let’s discuss an illustration of the difference between [ and [[ to solidify our understanding! :)
  • Below we see an usual pepper shaker, and let it be our list x.

  • x[1] is a pepper shaker containing a single pepper packet:

x[2] would look the same, but would contain the second packet. x[1:2] would be a pepper shaker containing two pepper packets.

  • x[[1]] is:

  • x[[1]][[1]] to get the content of the pepper package:

13.5.4 Exercises

  1. Draw the following lists as nested sets:
list(list(list(list(list(list(a))))))
list(a, b, list(c, d), list(e, f))

To draw pretty a visual diagram, refer to DiagramR R Package to render Graphviz diagrams.

But what I have is hand-drawn. Not pretty!! :)

For a:

For b:

2. What happens if you subset a tibble as if you’re subsetting a list? What are the key differences between a list and a tibble?

Subsetting a tibble works the same way as a list; a data frame can be thought of as a list of columns.

The key difference between a list and a tibble -> all the elements (columns) of a tibble must have the same length (number of rows). Lists can have vectors with different lengths as elements.

x <- tibble(a = 1:2, b = 3:4)
x[["a"]]
x["a"]
x[1]
x[1, ]