R flatten out list hierarchy to matrix or data.frame

list, matrix, r

Solution

Here is a solution. So it reads easily here, I have broken the code into two parts. Later, you can easily merge the two parts into a single function.

First, a function that gets a matrix of all the names, using recursion:

anames <- function(x) {

   require(plyr)
   if (is.data.frame(x)) return(NA)

   y <- do.call(rbind.fill.matrix,
                mapply(cbind, names(x), lapply(x, anames),
                       SIMPLIFY = FALSE))
   colnames(y) <- NULL

   return(y)
}

anames(a)
#      [,1] [,2] [,3] [,4]
# [1,] "b1" "c1" "d1" NA  
# [2,] "b1" "c2" NA   NA  
# [3,] "b2" NA   NA   NA

Then, a function that applies the given `steps` input, and fills the `NA`s like you requested:

listToMatrix <- function(myList, steps = Inf) {

   a <- anames(myList)
   steps <- min(steps, ncol(a) - 1)
   cols.idx <- seq_len(steps)
   a <- a[, cols.idx]
   for (j in tail(cols.idx, -1))
      a[, j] <- ifelse(is.na(a[, j]), a[, j - 1], a[, j])

   return(a)
}

listToMatrix(a, 2)
#      [,1] [,2]
# [1,] "b1" "c1"
# [2,] "b1" "c2"
# [3,] "b2" "b2"

Problem

I would like to flatten out a list hierarchy (similar to JSON) to a matrix or data frame. Let's say that I create the following list: ``` a <- list( b1 = list( c1 = list( d1 = data.frame() ), c2 = data.frame() ), b2 = data.frame() ) ``` Where each letter is another level or step down the hierarchy. Then I want a function, e.g. `listToMatrix(mylist = a, steps = 2)`, that generates the following: ``` [,1] [,2] [1,] "b1" "c1" [2,] "b1" "c2" [3,] "b2" "b2" ``` Observe that the function's argument `steps = 2` imply that it should only go 2 steps down the hierarchy. Also, if there aren't enough levels available in one direction, see `b2`, then it should keep the previous list name in the matrix. Any suggestions? :)

Original source