2

I come from a Python background but have to learn R for a job, and I am confused about lists.

I understand named lists can be (roughly) equivalent to Python dictionaries, and I can look up elements either by index using example_list[[1]] or example_list$name if I know the name of the key.

example_list <- list(a=1, b=3, c="d", f=list(1:4))

example_list$c #"d"
example_list$f #[[1]] [1] 1 2 3 4
example_list$f[[1]] # [1] 1 2 3 4
example_list[["f"]][[1]][[1]] # [1] 1

When I was playing around, I noticed to get "1" from f, I had to use [[1]] twice? I was expecting f to be [1, 2, 3, 4] but it seems to be [[1,2,3,4]], am I understanding this correctly?

2
  • Hi, you created a list inside a list, which is "f". Try f=c(1:4) Commented Jul 9 at 22:01
  • 3
    @flaviomcosta the c() is completely unnecessary. f=1:4 would be fine.
    – MrFlick
    Commented Jul 9 at 22:26

2 Answers 2

9

Keep in mind the distinction in R between lists and vectors. In R, 1:4 is a vector. list(1:4) is a list of length 1 that contains a vector of length 4. as.list(1:4) is a list of length 4 where each element contains a vector of length 1.

Consider these alternatives

example_list <- list(a=1, b=3, c="d", f=1:4)
example_list[["f"]][1]
# [1] 1
example_list$f[1]
# [1] 1

or

example_list <- list(a=1, b=3, c="d", f=as.list(1:4))
example_list$f[[1]]
# [1] 1
example_list[["f"]][[1]]
# [1] 1

or

example_list <- list(a=1, b=3, c="d", f=list(1,2,3,4))
example_list$f[[1]]
# [1] 1
example_list[["f"]][[1]]
# [1] 1

In your case you added an extra level of nesting with the list() call which you wouldn't normally use if just storing a vector. list(1:4) is different than list(1,2,3,4)

If it makes it easier to understand, you can also look at the JSON representation to see the extra layer of nesting

example_list <- list(a=1, b=3, c="d", f=list(1:4))
jsonlite::toJSON(example_list, auto_unbox = TRUE)
# {"a":1,"b":3,"c":"d","f":[[1,2,3,4]]} 
0
2

@MrFlick gives a good explanation of the details (though I have one nit to pick below). I'll add a little bit of (hopefully) useful information.

In R, you use [[ ]] to extract an element, and [ ] to subset a vector. The $ operator is a version of [[ ]] with some syntax differences.

So with example_list <- list(a=1, b=3, c="d", f=1:4), you'd read your expressions as follows:

example_list$c           # Extract the element named c
example_list$f           # Extract the element named f
example_list$f[[1]]      # Extract the first element of the element named f 

# and finally,

example_list[["f"]][[1]][[1]] 
# Extract the first element of the first element of the element named f

My one nitpick with @MrFlick's answer is when he says there's "a distinction between lists and vectors". Lists are a kind of vector, where the elements are R objects. Other kinds of vectors hold things like numbers or strings.

You can use the subsetting operator [ ] on any kind of vector, including lists. For example:

example_list[1:2]    # The first two elements of the list
                     # returned as a list with two elements

x <- c("a", "b", "c")
x[1:2]               # The first two elements of x
                     # returned as a character vector with two elements

You can also use [[ ]] on other vectors, but it's not very useful. For example

x[[1]]

extracts the first string from x, but since R doesn't allow you to have strings outside a vector, it puts the result in a new length 1 character vector. You end up with the same result as x[1] even though the thinking is different.

Not the answer you're looking for? Browse other questions tagged or ask your own question.