Search code examples
rlistcoercion

Unlisting nested lists and without loosing object classes


After a previous post regarding coercion of variables into their appropriate format, I realized that the problem is due to unlist():ing, which appears to kill off the object class of variables.

Consider a nested list (myList) of the following structure

> str(myList)
List of 2
 $ lst1:List of 3
  ..$ var1: chr [1:4] "A" "B" "C" "D"
  ..$ var2: num [1:4] 1 2 3 4
  ..$ var3: Date[1:4], format: "1999-01-01" "2000-01-01" "2001-01-01" "2002-01-01"
 $ lst2:List of 3
  ..$ var1: chr [1:4] "Q" "W" "E" "R"
  ..$ var2: num [1:4] 11 22 33 44
  ..$ var3: Date[1:4], format: "1999-01-02" "2000-01-03" "2001-01-04" "2002-01-05"

which contains different object types (character, numeric and Date) at the lowest level. I`ve been using

myNewLst <- lapply(myList, function(x) unlist(x,recursive=FALSE))
result <- do.call("rbind", myNewLst)

to get the desired structure of my resulting matrix. However, this yields a coercion into character for all variables, as seen here:

> str(result)
 chr [1:2, 1:12] "A" "Q" "B" "W" "C" "E" "D" "R" "1" "11" "2" "22" "3" "33" "4" "44" "10592" "10593" "10957" "10959" "11323" "11326" ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:2] "lst1" "lst2"
  ..$ : chr [1:12] "var11" "var12" "var13" "var14" ...

After reading a post on a similar issue, I've attempted to utilize do.call("c", x)

myNewLst <- lapply(myList, function(x) do.call("c", x))
result <- do.call("rbind", myNewLst)

Unfortunately, this also results in all variables being characters, as my first attempt. So my question is: How do I unlist a nested list without loosing the object class of my lower-level variables? Are there alternatives which will accomplish the desired result?

Reproducible code for myList:

myList <- list(
  "lst1" = list(
    "var1" = c("A","B","C","D"),
    "var2" = c(1,2,3,4),
    "var3" = c(as.Date('1999/01/01'),as.Date('2000/01/01'),as.Date('2001/01/01'),as.Date('2002/01/01'))
  ),
  "lst2" = list(
    "var1" = c("Q","W","E","R"),
    "var2" = c(11,22,33,44),
    "var3" = c(as.Date('1999/01/02'),as.Date('2000/01/03'),as.Date('2001/01/4'),as.Date('2002/01/05'))
  )
)

Solution

  • You can use Reduce() or do.call() to be able to combine all of the to one dataframe. The code below should work

          Reduce(rbind,lapply(myList,data.frame,stringsAsFactors=F))
    
            var1 var2       var3
          1    A    1 1999-01-01
          2    B    2 2000-01-01
          3    C    3 2001-01-01
          4    D    4 2002-01-01
          5    Q   11 1999-01-02
          6    W   22 2000-01-03
          7    E   33 2001-01-04
          8    R   44 2002-01-05
    

    Also the class is maintained:

      mapply(class,Reduce(rbind,lapply(myList,data.frame,stringsAsFactors=F)))
            var1        var2        var3 
     "character"   "numeric"      "Date"