How can I use the dollar sign operator $ to refer to elements of lists *inside* a list in R (or a tibble column if that's different)?

I can enter something like

list(3, 4, 5, 4, 3, 2, 2, 3, 2, 3, 4, 1, 1, 2, 1, 3) == 3

and get back


which is great because it means that I don’t have to clumsily use lapply() to get R to do what I want. But what if I have a list of lists, where the inner lists have named elements. For example, I could have a list of books, where each book is a list consisting of a $title and a $year in which it was published. Let’s say I have a tibble called books with just 1 column called book that is this list of books. How would I filter for only books published before 2000, or mutate() a column containing the titles?

The naive approach I would take to trying to filter by year is:

filter(books, book$year < 2000)

because I want it to go through each element of books$book and then look at the $year element of that, but, since books$book is itself a list, R looks for something named books$book$year instead of looking for the $year element of each element inside of books$book. How do I get around this without using lapply()?

Just for completeness, here is the (somewhat clumsy looking) way I do it with lapply():

filter(books, as.logical(lapply(books$book, function(x) x$year < 2000)))

>Solution :

You can use the code that you provide above, but you can simplify it to this:

filter(books,sapply(book, \(x) x$year<2000))

Instead of

filter(books, as.logical(lapply(books$book, function(x) x$year < 2000)))

The two changes are:

  • use sapply() instead of lapply() which will obviate the need for as.logical()
  • use the \(x) shortcut for function(x)

If you really don’t want to use lapply/sapply, you can, as @akrun suggests, switch to map_lgl, although with a slight simplification:

filter(books, map_lgl(book,~x$year<2000))

Leave a Reply