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? :)
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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With