Convert list of array/matrix into an array in R

Array and matrix/tables are data structures in R with same data types such as numeric, string or boolean. This examples show how to convert a list of vector/matrix/array into a multi-dimentional array so that it will become easier to aggregate them in particular dimension. We can also do this converting everything into data frame but this way can be useful sometimes and is worth learning.

Let us use a dataset already available in R and convert that into a list of tables or matrix. Here I will use Titanic dataset and convert it into a nested list of array using purrr package.

library(purrr)
titanic_list <- array_tree(Titanic, 4:3)
str(titanic_list)
List of 2
 $ No :List of 2
  ..$ Child: num [1:4, 1:2] 0 0 35 0 0 0 17 0
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ Class: chr [1:4] "1st" "2nd" "3rd" "Crew"
  .. .. ..$ Sex  : chr [1:2] "Male" "Female"
  ..$ Adult: num [1:4, 1:2] 118 154 387 670 4 13 89 3
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ Class: chr [1:4] "1st" "2nd" "3rd" "Crew"
  .. .. ..$ Sex  : chr [1:2] "Male" "Female"
 $ Yes:List of 2
  ..$ Child: num [1:4, 1:2] 5 11 13 0 1 13 14 0
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ Class: chr [1:4] "1st" "2nd" "3rd" "Crew"
  .. .. ..$ Sex  : chr [1:2] "Male" "Female"
  ..$ Adult: num [1:4, 1:2] 57 14 75 192 140 80 76 20
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ Class: chr [1:4] "1st" "2nd" "3rd" "Crew"
  .. .. ..$ Sex  : chr [1:2] "Male" "Female"

Following function will convert this nested array into a multi-dimensional array.

list2array <- function(list, dnames.name = NULL) {
  l2a <- function(l) {
    do.call(abind::abind, append(l, list(rev.along = 0)))
  }
  while (is.list(list[[1]])) {
    list <- map(list, l2a)
  }
  out <- l2a(list)
  if (!is.null(dnames.name)) names(dimnames(out)) <- dnames.name
  return(out)
}

Now, testing the function we just created.

NewTitanic <- list2array(titanic_list, dnames.name = names(dimnames(Titanic)))
str(NewTitanic)
 num [1:4, 1:2, 1:2, 1:2] 0 0 35 0 0 0 17 0 118 154 ...
 - attr(*, "dimnames")=List of 4
  ..$ Class   : chr [1:4] "1st" "2nd" "3rd" "Crew"
  ..$ Sex     : chr [1:2] "Male" "Female"
  ..$ Age     : chr [1:2] "Child" "Adult"
  ..$ Survived: chr [1:2] "No" "Yes"
identical(Titanic, as.table(NewTitanic))
[1] TRUE