How to extract sublists based on variable name in R

I have lists deep within lists and I want to extract all matrices with name a from the code below and store all these matrices into asingle list, say matlist. Please can anyone suggest how to do this. Thank you in advance

x <- list()
x[[1]] <- list()
x[[1]][[1]] <- list()
x[[1]][[2]] <- list()

x[[2]] <- list()
x[[2]][[1]] <- list()
x[[2]][[2]] <- list()

x[[3]] <- list()
x[[3]][[1]] <- list()
x[[3]][[2]] <- list()


x[[1]][[1]]$a <- matrix(rnorm(4),2,2)
x[[1]][[1]]$b <- 3
x[[1]][[2]]$a <- matrix(rnorm(4),2,2)
x[[1]][[2]]$b <- 3
x[[2]][[1]]$a <- matrix(rnorm(4),2,2)
x[[2]][[1]]$b <- 2
x[[2]][[2]]$a <- matrix(rnorm(4),2,2)
x[[2]][[2]]$b <- 2
x[[3]][[1]]$a <- matrix(rnorm(4),2,2)
x[[3]][[1]]$b <- 1
x[[3]][[2]]$a <- matrix(rnorm(4),2,2)
x[[3]][[2]]$b <- 1

Upvotes: 0

Views: 323

Answers (3)

GKi
GKi

Reputation: 39647

You can use [[ in lapply with a after using unlist for one level to extract lists within lists based on variable name.

matlist <- lapply(unlist(x, FALSE), "[[", "a")
matlist
#[[1]]
#           [,1]      [,2]
#[1,] -0.2164749 0.1255995
#[2,]  0.9368159 1.0416349
#
#[[2]]
#          [,1]       [,2]
#[1,] -2.188259 -0.2364393
#[2,] -3.003292  1.2006254
#
#[[3]]
#          [,1]     [,2]
#[1,]  1.089767 1.059162
#[2,] -2.043437 1.428467
#
#[[4]]
#           [,1]      [,2]
#[1,] -0.1984872  1.194170
#[2,] -0.9998112 -2.875852
#
#[[5]]
#           [,1]        [,2]
#[1,]  1.4556923 -0.05156698
#[2,] -0.4252525 -0.64838966
#
#[[6]]
#           [,1]      [,2]
#[1,]  0.2450849 0.6129029
#[2,] -0.2372427 0.2555269

Or in case you want to keep the structure of sub lists like purrr:map_depth is doing a recursive function call is possible:

f <- function(x, n) {
  if(!is.null(names(x)) & n %in% names(x)) x[[n]]
  else if(is.list(x)) lapply(x, f, n)
}
matlist <- f(x, "a")
matlist
#[[1]]
#[[1]][[1]]
#           [,1]      [,2]
#[1,] -0.2164749 0.1255995
#[2,]  0.9368159 1.0416349
#
#[[1]][[2]]
#          [,1]       [,2]
#[1,] -2.188259 -0.2364393
#[2,] -3.003292  1.2006254
#
#
#[[2]]
#[[2]][[1]]
#          [,1]     [,2]
#[1,]  1.089767 1.059162
#[2,] -2.043437 1.428467
#
#[[2]][[2]]
#           [,1]      [,2]
#[1,] -0.1984872  1.194170
#[2,] -0.9998112 -2.875852
#
#
#[[3]]
#[[3]][[1]]
#           [,1]        [,2]
#[1,]  1.4556923 -0.05156698
#[2,] -0.4252525 -0.64838966
#
#[[3]][[2]]
#           [,1]      [,2]
#[1,]  0.2450849 0.6129029
#[2,] -0.2372427 0.2555269

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 388817

You can use lapply as :

lapply(x, function(x) {
  x1 <- unlist(x, recursive = FALSE)
  do.call(rbind, x1[names(x1) == 'a'])
}) -> x1

x1

#[[1]]
#           [,1]        [,2]
#[1,]  0.3031708  0.09749503
#[2,]  0.9608749  0.51528005
#[3,] -0.6591001  0.09854767
#[4,] -1.6979551 -0.11709249

#[[2]]
#            [,1]       [,2]
#[1,] -1.11747169 -0.5668559
#[2,] -0.87458122  0.2517329
#[3,] -0.01483449 -1.7775506
#[4,]  1.57139735 -0.3488897

#[[3]]
#           [,1]        [,2]
#[1,] -0.2880580 -0.07233675
#[2,]  0.2933759  0.73729995
#[3,]  0.1070971 -0.27202774
#[4,] -0.5881883 -1.27391810

If you want everything combined into one you can do do.call(rbind, x1).

Upvotes: 1

Łukasz Deryło
Łukasz Deryło

Reputation: 1860

This time purrr:map_depth is your friend:

library(purrr)

map_depth(x, .depth = 2, 'a')

[[1]]
[[1]][[1]]
          [,1]      [,2]
[1,] 2.0693923  2.142611
[2,] 0.6840833 -1.440975

[[1]][[2]]
           [,1]       [,2]
[1,]  0.5415685 -0.7262725
[2,] -0.1604015  0.5218570


[[2]]
[[2]][[1]]
           [,1]          [,2]
[1,]  0.1245714  8.887078e-05
[2,] -0.2137517 -9.737122e-01

[[2]][[2]]
          [,1]       [,2]
[1,] 0.1993254  0.1116033
[2,] 0.5058125 -1.8523019


[[3]]
[[3]][[1]]
           [,1]        [,2]
[1,]  0.8661770 -1.76328811
[2,] -0.4559405 -0.08104821

[[3]][[2]]
          [,1]       [,2]
[1,] 0.7247404 -2.6736933
[2,] 0.8053027  0.5735254

Upvotes: 1

Related Questions