Transpose a List of Lists

后端 未结 5 1999
我寻月下人不归
我寻月下人不归 2020-12-01 23:32

I have a list which contains list entries, and I need to transpose the structure. The original structure is rectangular, but the names in the sub-lists do not match.

相关标签:
5条回答
  • 2020-12-02 00:01

    While this is an old question, i found it while searching for the same problem, and the second hit on google had a much more elegant solution in my opinion:

    list_of_lists <- list(a=list(x="ax", y="ay"), b=list(w="bw", z="bz"))
    new <- do.call(rbind, list_of_lists) 
    

    new is now a rectangular structure, a strange object: A list with a dimension attribute. It works with as many elements as you wish, as long as every sublist has the same length. To change it into a more common R-Object, one could for example create a matrix like this:

    new.dims <- dim(new)
    matrix(new,nrow = new.dims[1])
    

    new.dims needed to be saved, as the matrix() function deletes the attribute of the list. Another way:

    new <- do.call(c, new) 
    dim(new) <- new.dims
    

    You can now for example convert it into a data.frame with as.data.frame() and split it into columns or do column wise operations. Before you do that, you could also change the dim attribute of the matrix, if it fits your needs better.

    0 讨论(0)
  • 2020-12-02 00:04

    I found myself with this problem but I needed a solution that kept the names of each element. The solution I came up with should also work when the sub lists are not all the same length.

    invertList = function(l){
      elemnames = NULL
      for (i in seq_along(l)){
        elemnames = c(elemnames, names(l[[i]]))
      }
    
      elemnames = unique(elemnames)
    
      res = list()
      for (i in seq_along(elemnames)){
        res[[elemnames[i]]] = list()
        for (j in seq_along(l)){
          if(exists(elemnames[i], l[[j]], inherits = F)){
            res[[i]][[names(l)[j]]] = l[[names(l)[j]]][[elemnames[i]]]
          }
        }
      }
      res
    }
    
    0 讨论(0)
  • 2020-12-02 00:09

    Here's a different idea - use the fact that data.table can store data.frame's (in fact, given your question, maybe you don't even need to work with lists of lists and could just work with data.table's):

    library(data.table)
    
    dt = as.data.table(before)
    after = as.list(data.table(t(dt)))
    
    0 讨论(0)
  • 2020-12-02 00:26

    The following piece of code will create a list with i-th element of every list in before:

    lapply(before, "[[", i)
    

    Now you just have to do

    n <- length(before[[1]]) # assuming all lists in before have the same length
    lapply(1:n, function(i) lapply(before, "[[", i))
    

    and it should give you what you want. It's not very efficient (travels every list many times), and you can probably make it more efficient by keeping pointers to current list elements, so please decide whether this is good enough for you.

    0 讨论(0)
  • 2020-12-02 00:26

    The purrr package now makes this process really easy:

    library(purrr)
    
    before %>% transpose()
    
    ## $x
    ## $x$a
    ##   a x
    ## 1 1 2
    ## 
    ## $x$b
    ##   b w
    ## 1 5 6
    ## 
    ## 
    ## $y
    ## $y$a
    ##   a y
    ## 1 3 4
    ## 
    ## $y$b
    ##   b z
    ## 1 7 8
    
    0 讨论(0)
提交回复
热议问题