我有一个包含列表条目的列表,我需要转置结构。 原始结构是矩形的,但子列表中的名称不匹配。
以下是一个例子:
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结构。这样做的惯用方法是什么?
答案 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
}