Subset nested list based on element name in R

Viewed 139

I have 3 lists called T1, T2, and T3 (shown below). From these lists, I want to extract a subset Q.

L1<-list("A"=matrix(c(1:4),2),"B"=matrix(c("a","b","c","d"),2))
L2<-list("P"=matrix(c(5:8),2),"Q"=list(list("u","v","w","x"),2))

T1 <- list(L1, L2)
T2 <- list(NULL, L1, L2)
T3 <- list(L1, NULL, L2)

The output I need is only the list Q which is embedded in the parent lists (T1, T2, and T3).

Here are the solutions I tried, but they all return the NULL value for siblings of Q -

lapply(T3, `[[`, "Q")
purrr::map(T3, `[`, "Q")
purrr::map_depth(T3, 2, "Q")

Please suggest a solution to subset Q out of parents T1, T2, and T3. As you can see the position of Q is different in each parent, I am looking for a solution to subset parent list by child name Q instead of hardcoding the position of Q.

3 Answers

You can unlist the parent list with recursive = FALSE, and get a single merged list. Then you can access Q as :

unlist(T1, recursive = FALSE)$Q
unlist(T2, recursive = FALSE)$Q
unlist(T3, recursive = FALSE)$Q

There's no base function that does that. Normally you want to preserve the length of the input when you are mapping/applying over list. You could write a helper function that just returns the first match

first_match <- function(x, name) {
  for (list in x) {
    if (name %in% names(list)) {
      return(list[[name]])
    }
  }
  return(NULL)
}

first_match(T1, "Q")
first_match(T2, "Q")
first_match(T3, "Q")

Using an external package, this can also be done with rrapply() in the rrapply-package:

library(rrapply)

Q1 <- rrapply(T1, classes = "list", condition = \(x, .xname) .xname == "Q", how = "flatten")
Q2 <- rrapply(T2, classes = "list", condition = \(x, .xname) .xname == "Q", how = "flatten")
Q3 <- rrapply(T3, classes = "list", condition = \(x, .xname) .xname == "Q", how = "flatten")

str(Q1)
#> List of 1
#>  $ Q:List of 2
#>   ..$ :List of 4
#>   .. ..$ : chr "u"
#>   .. ..$ : chr "v"
#>   .. ..$ : chr "w"
#>   .. ..$ : chr "x"
#>   ..$ : num 2
Related