转置列表列表

时间:2013-04-23 21:07:34

标签: r

我有一个包含列表条目的列表,我需要转置结构。 原始结构是矩形的,但子列表中的名称不匹配。

以下是一个例子:

ax <- data.frame(a=1,x=2)
ay <- data.frame(a=3,y=4)
bw <- data.frame(b=5,w=6)
bz <- data.frame(b=7,z=8)
before <- list(  a=list(x=ax, y=ay),   b=list(w=bw, z=bz))

我想要的是什么:

after  <- list(w.x=list(a=ax, b=bw), y.z=list(a=ay, b=bz))

我不关心结果列表的名称(在任何级别)。

显然,这可以明确地完成:

after <- list(x.w=list(a=before$a$x, b=before$b$w), y.z=list(a=before$a$y, b=before$b$z))

但这很难看,仅适用于2x2结构。这样做的惯用方法是什么?

5 个答案:

答案 0 :(得分:19)

以下代码将创建一个列表,其中包含before中每个列表的第i个元素:

lapply(before, "[[", i)

现在你必须做

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

它应该给你你想要的东西。它效率不高(每次列表多次传输),你可以通过保持指向当前列表元素的指针来提高效率,所以请确定这对你来说是否足够好。

答案 1 :(得分:8)

purrr包现在使这个过程非常简单:

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

答案 2 :(得分:5)

这是一个不同的想法 - 使用data.table可以存储data.frame的事实(事实上,考虑到你的问题,也许你甚至不需要使用列表列表,而且可能只是与data.table的合作:

library(data.table)

dt = as.data.table(before)
after = as.list(data.table(t(dt)))

答案 3 :(得分:3)

虽然这是一个老问题,我在搜索同样的问题时发现了它,而second hit on google在我看来有一个更优雅的解决方案:

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

new现在是一个矩形结构,一个奇怪的对象:一个带有维度属性的列表。只要每个子列表具有相同的长度,它就可以使用任意多个元素。要将其更改为更常见的R-Object,可以创建如下矩阵:

new.dims <- dim(new)
matrix(new,nrow = new.dims[1])
需要保存

new.dims,因为matrix()函数会删除列表的属性。另一种方式:

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

现在,您可以将其转换为带有as.data.frame()的data.frame,并将其拆分为列或执行列式操作。在您这样做之前,您还可以更改矩阵的dim属性,如果它更符合您的需求。

答案 4 :(得分:1)

我发现自己遇到了这个问题,但我需要一个能够保存每个元素名称的解决方案。当子列表的长度不同时,我提出的解决方案也应该有效。

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
}