R: how to rearrange a list object

Viewed 79
mylist <- list(matrix(c(1, 2, 3, "red", "blue", "green", "apple", "banana", "orange"), ncol = 3, nrow = 3), 
               matrix(c(2, 3, 9, "green", "blue", "green", "apple", "guava", "orange"), ncol = 3, nrow = 3), 
               matrix(c(43, 90, 1, "black", "red", "green", "orange", "watermelon", "orange"), ncol = 3, nrow = 3))
> mylist
[[1]]
     [,1] [,2]    [,3]    
[1,] "1"  "red"   "apple" 
[2,] "2"  "blue"  "banana"
[3,] "3"  "green" "orange"

[[2]]
     [,1] [,2]    [,3]    
[1,] "2"  "green" "apple" 
[2,] "3"  "blue"  "guava" 
[3,] "9"  "green" "orange"

[[3]]
     [,1] [,2]    [,3]        
[1,] "43" "black" "orange"    
[2,] "90" "red"   "watermelon"
[3,] "1"  "green" "orange"   

In mylist, I have 3 sublists. Each sublist contains a 3x3 matrix, where the first column contains numbers, second contains colors, and third contains fruits.

I want to re-arrange these sublists such that the matrix in the first sublist contains numbers, the second contains colors, and the third contains fruits. That is, I want it to look something like this:

[[1]]
     [,1] [,2] [,3]
[1,]    1    2   43
[2,]    2    3   90
[3,]    3    9    1

[[2]]
     [,1]    [,2]    [,3]   
[1,] "red"   "green" "black"
[2,] "blue"  "blue"  "red"  
[3,] "green" "green" "green"

[[3]]
     [,1]     [,2]     [,3]        
[1,] "apple"  "apple"  "orange"    
[2,] "banana" "guava"  "watermelon"
[3,] "orange" "orange" "orange"   

My intuition is to use lapply to loop through the columns of the matrices and store them in a new list, but I'm not sure how to efficiently go about this.

3 Answers

You can bind, split by column and convert back to matrices:

lapply(asplit(do.call(rbind, mylist), 2), matrix, 3)

[[1]]
     [,1] [,2] [,3]
[1,] "1"  "2"  "43"
[2,] "2"  "3"  "90"
[3,] "3"  "9"  "1" 

[[2]]
     [,1]    [,2]    [,3]   
[1,] "red"   "green" "black"
[2,] "blue"  "blue"  "red"  
[3,] "green" "green" "green"

[[3]]
     [,1]     [,2]     [,3]        
[1,] "apple"  "apple"  "orange"    
[2,] "banana" "guava"  "watermelon"
[3,] "orange" "orange" "orange"    

A short base R method without any lapply calls:

asplit(`dim<-`(do.call(rbind, mylist), c(3, 3, 3)), 3)
#> [[1]]
#>      [,1] [,2] [,3]
#> [1,] "1"  "2"  "43"
#> [2,] "2"  "3"  "90"
#> [3,] "3"  "9"  "1" 
#> 
#> [[2]]
#>      [,1]    [,2]    [,3]   
#> [1,] "red"   "green" "black"
#> [2,] "blue"  "blue"  "red"  
#> [3,] "green" "green" "green"
#> 
#> [[3]]
#>      [,1]     [,2]     [,3]        
#> [1,] "apple"  "apple"  "orange"    
#> [2,] "banana" "guava"  "watermelon"
#> [3,] "orange" "orange" "orange"

You can unlist and then split it into a list again. I've added a type.convert in there to convert the first set of values to numeric.

lapply(split(unlist(mylist), rep(1:3, each = 3)), function(x) matrix(type.convert(x), 3))
## $`1`
##      [,1] [,2] [,3]
## [1,]    1    2   43
## [2,]    2    3   90
## [3,]    3    9    1
## 
## $`2`
##      [,1]    [,2]    [,3]   
## [1,] "red"   "green" "black"
## [2,] "blue"  "blue"  "red"  
## [3,] "green" "green" "green"
## 
## $`3`
##      [,1]     [,2]     [,3]        
## [1,] "apple"  "apple"  "orange"    
## [2,] "banana" "guava"  "watermelon"
## [3,] "orange" "orange" "orange"    
## 
Related