I want to create interleaved matrix from a list of matrices.
Example input:
> l <- list(a=matrix(1:4,2),b=matrix(5:8,2))
> l
$a
[,1] [,2]
[1,] 1 3
[2,] 2 4
$b
[,1] [,2]
[1,] 5 7
[2,] 6 8
Expected output:
1 3
5 7
2 4
6 8
I have checked the interleave function in gdata but it does not show this behaviour for lists. Any help appreciated.
Here is a one-liner:
do.call(rbind, l)[order(sequence(sapply(l, nrow))), ]
# [,1] [,2]
# [1,] 1 3
# [2,] 5 7
# [3,] 2 4
# [4,] 6 8
To help understand, the matrices are first stacked on top of each other with do.call(rbind, l)
, then the rows are extracted in the right order:
sequence(sapply(l, nrow))
# a1 a2 b1 b2
# 1 2 1 2
order(sequence(sapply(l, nrow)))
# [1] 1 3 2 4
It will work with any number of matrices and it will do "the right thing" (subjective) even if they don't have the same number of rows.
Rather than reinventing the wheel, you can just modify it to get you to your destination.
The interleave
function from "gdata" starts with ...
to let you specify a number of data.frame
s or matrices to put together. The first few lines of the function look like this:
head(interleave)
#
# 1 function (..., append.source = TRUE, sep = ": ", drop = FALSE)
# 2 {
# 3 sources <- list(...)
# 4 sources[sapply(sources, is.null)] <- NULL
# 5 sources <- lapply(sources, function(x) if (is.matrix(x) ||
# 6 is.data.frame(x))
You can just rewrite lines 1 and 3 as I did in this Gist to create a list
version of interleave
(here, I've called it Interleave
)
head(Interleave)
#
# 1 function (myList, append.source = TRUE, sep = ": ", drop = FALSE)
# 2 {
# 3 sources <- myList
# 4 sources[sapply(sources, is.null)] <- NULL
# 5 sources <- lapply(sources, function(x) if (is.matrix(x) ||
# 6 is.data.frame(x))
Does it work?
l <- list(a=matrix(1:4,2),b=matrix(5:8,2), c=matrix(9:12,2))
Interleave(l)
# [,1] [,2]
# a 1 3
# b 5 7
# c 9 11
# a 2 4
# b 6 8
# c 10 12
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