R - Subsetting list by paramaters of nested list

Viewed 286

I have a list list_tot that has nested lists.

I want to subset or create a new list that selects specific subsets based on the parameters specified, details follow:

List_1 <- list(a = matrix(5,2), b = matrix(5,7), c = matrix(5,9), d = matrix(5,3))
List_2 <- list(a = matrix(7,3), b = matrix(7,7), c = matrix(7,1), d = matrix(7,9))
List_3 <- list(a = matrix(5,2), b = matrix(5,7), c = matrix(5,9), d = matrix(5,3))
List_4 <- list(a = matrix(5,2), b = matrix(5,7), c = matrix(5,9), d = matrix(5,3))
List_5 <- list(a = matrix(5,2), b = matrix(5,7), c = matrix(5,9), d = matrix(5,3))

List_tot <- list(List_1, List_2, List_3, List_4, List_5)

that reads:

[[1]]

[[1]]$a
     [,1]
[1,]    5
[2,]    5

[[1]]$b
     [,1]
[1,]    5
[2,]    5
[3,]    5
[4,]    5
[5,]    5
[6,]    5
[7,]    5

[[1]]$c
      [,1]
 [1,]    5
 [2,]    5
 [3,]    5
 [4,]    5
 [5,]    5
 [6,]    5
 [7,]    5
 [8,]    5
 [9,]    5

[[1]]$d
     [,1]
[1,]    5
[2,]    5
[3,]    5


[[2]]
[[2]]$a
     [,1]
[1,]    7
[2,]    7
[3,]    7

[[2]]$b
     [,1]
[1,]    7
[2,]    7
[3,]    7
[4,]    7
[5,]    7
[6,]    7
[7,]    7

[[2]]$c
     [,1]
[1,]    7
...etc

I want to select:

  1. for each nested list only select list/matrix a, c, and d.
  2. for each nested list select two lists/matrices with the top number of rows.

So New_List_tot would have an output of:

that reads:

[[1]]

[[1]]$c
      [,1]
 [1,]    5
 [2,]    5
 [3,]    5
 [4,]    5
 [5,]    5
 [6,]    5
 [7,]    5
 [8,]    5
 [9,]    5

[[1]]$d
     [,1]
[1,]    5
[2,]    5
[3,]    5
etc...

Any assistance would be helpful. All my attempts, attempts using plyer and dplyr, but with no success and very much stuck.

4 Answers

We can use base R to do this. No packages are needed

lapply(List_tot, `[`, c("a", "c", "d"))

or with anonymous function

lapply(List_tot, function(x) x[c("a", "c", "d")])

if we need the top 2, order the number of rows (lengths work as these are single column matrix, so the number of rows are equal to the total number of elements, get the head of the names of the ordered vector of number of rows and use that to extract the inner list element

lapply(List_tot, function(x) {
      x1 <- x[c("a", "c", "d")]
      v1 <- lengths(x1)
      x1[head(names(v1)[order(-v1)], 2)]
    })

Update

For the second goal, you can try

lapply(
  List_tot,
  function(lst) {
    head(lst[c("a", "c", "d")][order(-sapply(lst[c("a", "c", "d")], nrow))], 2)
  }
)

which gives

[[1]]
[[1]]$c
      [,1]
 [1,]    5
 [2,]    5
 [3,]    5
 [4,]    5
 [5,]    5
 [6,]    5
 [7,]    5
 [8,]    5
 [9,]    5

[[1]]$d
     [,1]
[1,]    5
[2,]    5
[3,]    5


[[2]]
[[2]]$d
      [,1]
 [1,]    7
 [2,]    7
 [3,]    7
 [4,]    7
 [5,]    7
 [6,]    7
 [7,]    7
 [8,]    7
 [9,]    7

[[2]]$a
     [,1]
[1,]    7
[2,]    7
[3,]    7


[[3]]
[[3]]$c
      [,1]
 [1,]    5
 [2,]    5
 [3,]    5
 [4,]    5
 [5,]    5
 [6,]    5
 [7,]    5
 [8,]    5
 [9,]    5

[[3]]$d
     [,1]
[1,]    5
[2,]    5
[3,]    5


[[4]]
[[4]]$c
      [,1]
 [1,]    5
 [2,]    5
 [3,]    5
 [4,]    5
 [5,]    5
 [6,]    5
 [7,]    5
 [8,]    5
 [9,]    5

[[4]]$d
     [,1]
[1,]    5
[2,]    5
[3,]    5


[[5]]
[[5]]$c
      [,1]
 [1,]    5
 [2,]    5
 [3,]    5
 [4,]    5
 [5,]    5
 [6,]    5
 [7,]    5
 [8,]    5
 [9,]    5

[[5]]$d
     [,1]
[1,]    5
[2,]    5
[3,]    5

  • For your first goal "for each nested list only select list/matrix a, c, and d."
lapply(List_tot, `[`, c("a", "c", "d"))
  • For your second goal "for each nested list select the lists/matrices with the top number of rows."
Map(`[`, List_tot, max.col(t(sapply(List_tot, lengths))))

In base R you could do:

lapply(List_tot, 
   function(x) (y<-x[c("a", "c", "d")])[order(sapply(y, nrow), decreasing  = TRUE)[1:2]])

[[1]]
[[1]]$c
      [,1]
 [1,]    5
 [2,]    5
 [3,]    5
 [4,]    5
 [5,]    5
 [6,]    5
 [7,]    5
 [8,]    5
 [9,]    5

[[1]]$d
     [,1]
[1,]    5
[2,]    5
[3,]    5
 etc

@akrun has a clean answer for step 1, filtering by columns. For step 2, filtering by number of rows you can try

library(magrittr)
List_colfilter <- lapply(List_tot, function(i)i[c("a","c","d")])

longestlist <- function(l){
  maxr <- lapply(l,nrow) %>% unlist %>% max
  l2 <- lapply(l, function(x) if(nrow(x)==maxr) x else NA)
  for (n in names(l)){
    if (is.na(l2[n])){
      l2[n] <- NULL
    }
  }
  return(l2)
}
List_longfilter <- lapply(List_colfilter, longestlist)
Related