Reputation: 3376
Suppose that A, B and C are matrices. And I have a list of them like this:
list(A,list(B,C))
I want to convert it to this:
list(A,B,C)
The unlist
function convert the matrices to vectors!
For example:
A=matrix(1:10,nrow=2)
B=list(A,list(A,A))
unlist(B)
Upvotes: 16
Views: 1817
Reputation: 52657
Here is a recursive implementation:
flatten2 <- function(X) if(is.list(X)) Reduce(c, lapply(X, flatten2)) else list(X)
Then:
str(flatten2(B)) # list of three matrices:
# List of 3
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
And more complex:
C <- list(A, list(list(A, A), A))
str(flatten2(C))
# List of 4
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
Also, a "wordier" but faster version (this is the one tested by Pierre):
flatten <- function(X) {
res <- list()
for(i in X) res <- c(res, if(is.list(i)) Recall(i) else list(i))
res
}
You could also make flatten2
a little faster by replacing Reduce
with do.call
, but that is a little less cute. flatten
remains the fastest even with that change.
Upvotes: 14
Reputation: 19031
You can use the list.flatten
function of the rlist package. An example:
library(rlist)
A1 <- matrix(1:10, nrow = 2)
A2 <- matrix(11:20, nrow = 2)
A3 <- matrix(21:30, nrow = 2)
B <- list(A1, list(A2, A3))
C <- list.flatten(B)
C
# [[1]]
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 3 5 7 9
# [2,] 2 4 6 8 10
#
# [[2]]
# [,1] [,2] [,3] [,4] [,5]
# [1,] 11 13 15 17 19
# [2,] 12 14 16 18 20
#
# [[3]]
# [,1] [,2] [,3] [,4] [,5]
# [1,] 21 23 25 27 29
# [2,] 22 24 26 28 30
str(C)
# List of 3
# $ : int [1:2, 1:5] 1 2 3 4 5 6 7 8 9 10
# $ : int [1:2, 1:5] 11 12 13 14 15 16 17 18 19 20
# $ : int [1:2, 1:5] 21 22 23 24 25 26 27 28 29 30
Upvotes: 7
Reputation: 28451
So many great solutions. I wanted to contribute a comparison:
library(microbenchmark)
microbenchmark(
flatten = flatten(lst),
delist = delist(lst),
list.flatten = list.flatten(lst))
# expr min lq mean median uq
# flatten 14.606 16.3830 19.17356 17.7640 18.5540
# delist 228.559 239.6115 251.52930 247.5070 254.0205
# list.flatten 51.318 56.0545 63.87871 61.7785 70.2660
# max neval
# 41.449 100
# 406.589 100
# 145.267 100
Data
A <- matrix(1e4, 100)
lst <- list(A, list(A, list(A, list(A, list(A, list(A, list(A)))))))
flatten <- function(X) {
res <- list()
for(i in X) res <- c(res, if(is.list(i)) Recall(i) else list(i))
res
}
delist<-function(x) {
lists <- sapply(x, class)=="list"
while(any(lists)) {
x<-mapply(function(y,z) if (!z) list(y) else (y), x, lists, SIMPLIFY=FALSE)
x<-do.call('c', x)
lists <- sapply(x, class)=="list"
}
x
}
library(rlist)
list.flatten
Upvotes: 5
Reputation: 206401
You could do something like this
delist<-function(x) {
lists <- sapply(x, class)=="list"
while(any(lists)) {
x<-mapply(function(y,z) if (!z) list(y) else (y), x, lists, SIMPLIFY=FALSE)
x<-do.call('c', x)
lists <- sapply(x, class)=="list"
}
x
}
with your example you get
delist(B)
# [[1]]
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 3 5 7 9
# [2,] 2 4 6 8 10
#
# [[2]]
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 3 5 7 9
# [2,] 2 4 6 8 10
#
# [[3]]
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 3 5 7 9
# [2,] 2 4 6 8 10
Upvotes: 12