18

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

这是一个例子:

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 结构。这样做的惯用方式是什么?

4

5 回答 5

22

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

lapply(before, "[[", i)

现在你只需要做

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

它应该给你你想要的。它的效率不是很高(多次遍历每个列表),您可以通过保留指向当前列表元素的指针来提高效率,因此请确定这对您来说是否足够好。

于 2013-04-23T21:33:48.477 回答
12

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
于 2016-07-10T15:27:23.277 回答
5

这是一个不同的想法 - 使用data.table可以存储data.frame's 的事实(事实上,鉴于您的问题,也许您甚至不需要使用列表列表而可以使用data.table's):

library(data.table)

dt = as.data.table(before)
after = as.list(data.table(t(dt)))
于 2013-04-23T22:15:59.337 回答
3

虽然这是一个老问题,但我在搜索同样的问题时发现了它,在我看来,谷歌的第二次点击有一个更优雅的解决方案:

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

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

于 2015-10-05T22:07:25.480 回答
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
}
于 2016-06-03T13:21:20.963 回答