给定一个列表列表,我的目标是改变其结构(R语言).
所以,我想将嵌套列表的元素作为第一层列表的元素.
可能更好地说明我的目的.鉴于:
z <- list(z1 = list(a = 1, b = 2, c = 3), z2 = list(b = 4, a = 1, c = 0))
Run Code Online (Sandbox Code Playgroud)
我想要一个等效于后续R对象的输出:
o <- list(a = list(z1 = 1, z2 = 1), b = list(z1 = 2, z2 = 4), c = list(z1 = 3, z2 = 0))
Run Code Online (Sandbox Code Playgroud)
我创建了自己的解决方案,我将在下面附上,但如果有更好的解决方案,请告诉我.
revert_list_str_1 <- function(ls) {
res <- lapply(names(ls[[1]]), function(n, env) {
name <- paste(n, 'elements', sep = '_')
assign(name, vector('list', 0))
inner <- sapply(ls, function(x) {
assign(name, c(get(name), x[which(names(x) == n)]))
})
names(inner) <- names(ls)
inner
})
names(res) <- names(ls[[1]])
res
}
Run Code Online (Sandbox Code Playgroud)
执行str(revert_list_str_1(z))
我获得后续输出,对应于我想要的.
List of 3
$ a:List of 2
..$ z1: num 1
..$ z2: num 1
$ b:List of 2
..$ z1: num 2
..$ z2: num 4
$ c:List of 2
..$ z1: num 3
..$ z2: num 0
Run Code Online (Sandbox Code Playgroud)
但正如我所说,我想研究(并学习)更优雅和动态解决方案的存在.
事实上,只有当所有嵌套列表具有相同的名称(也以不同的顺序)时,我的解决方案才能完全运行.这是因为names(ls[[1]])
.我还要指出,它只对2个级别的列表起作用,就像报告的那个级别一样.
那么,你知道其他更有活力的解决方案吗?可以rapply
和/或Filter
函数对此任务有用吗?
结束编辑1.
我已经对建议的解决方案进行了一些分析,大家都知道!.分析包括验证所有功能的以下几点:
在所有这些情况下,对于第2.1点,"是"的分类是正面的.
这是我考虑过的所有功能(评论与上面提到的分析项目有关):
# yes 1.1
# yes 1.2
# yes 2.1, not 2.2, not 2.3
revert_list_str_1 <- function(ls) { # @leodido
# see above
}
# not 1.1
# not 1.2
# not 2.1, not 2.2, not 2.3
revert_list_str_2 <- function(ls) { # @mnel
# convert each component of list to a data.frame
# so rbind.data.frame so named elements are matched
x <- data.frame((do.call(rbind, lapply(ls, data.frame))))
# convert each column into an appropriately named list
o <- lapply(as.list(x), function(i, nam) as.list(`names<-`(i, nam)), nam = rownames(x))
o
}
# yes 1.1
# yes 1.2
# yes 2.1, not 2.2, yes 2.3
revert_list_str_3 <- function(ls) { # @mnel
# unique names
nn <- Reduce(unique, lapply(ls, names))
# convert from matrix to list `[` used to ensure correct ordering
as.list(data.frame(do.call(rbind,lapply(ls, `[`, nn))))
}
# yes 1.1
# yes 1.2
# yes 2.1, not 2.2, yes 2.3
revert_list_str_4 <- function(ls) { # @Josh O'Brien
# get sub-elements in same order
x <- lapply(ls, `[`, names(ls[[1]]))
# stack and reslice
apply(do.call(rbind, x), 2, as.list)
}
# not 1.1
# not 1.2
# not 2.1, not 2.2, not 2.3
revert_list_str_5 <- function(ls) { # @mnel
apply(data.frame((do.call(rbind, lapply(ls, data.frame)))), 2, as.list)
}
# not 1.1
# not 1.2
# not 2.1, yes 2.2, yes 2.3
revert_list_str_6 <- function(ls) { # @baptiste + @Josh O'Brien
b <- recast(z, L2 ~ L1)
apply(b, 1, as.list)
}
# yes 1.1
# yes 1.2
# not 2.1, yes 2.2, yes 2.3
revert_list_str_7 <- function(ll) { # @Josh O'Brien
nms <- unique(unlist(lapply(ll, function(X) names(X))))
ll <- lapply(ll, function(X) setNames(X[nms], nms))
ll <- apply(do.call(rbind, ll), 2, as.list)
lapply(ll, function(X) X[!sapply(X, is.null)])
}
Run Code Online (Sandbox Code Playgroud)
从这一分析中可以看出:
revert_list_str_7
和revert_list_str_6
是最灵活的关于嵌套列表的名称revert_list_str_4
,revert_list_str_3
其次是我自己的功能是完整的,很好的权衡.revert_list_str_7
.为了完成这项工作,我microbenchmark
在这4个函数上做了一些小基准测试(使用R软件包)(每个基准测试的时间= 1000).
基准1
输入:
list(z1 = list(a = 1, b = 2, c = 3), z2 = list(a = 0, b = 3, d = 22, f = 9))
.
结果:
Unit: microseconds
expr min lq median uq max
1 func_1 250.069 467.5645 503.6420 527.5615 2028.780
2 func_3 204.386 393.7340 414.5485 429.6010 3517.438
3 func_4 89.922 173.7030 189.0545 194.8590 1669.178
4 func_6 11295.463 20985.7525 21433.8680 21934.5105 72476.316
5 func_7 348.585 387.0265 656.7270 691.2060 2393.988
Run Code Online (Sandbox Code Playgroud)
获胜者:revert_list_str_4
.
基准2
输入:
list(z1 = list(a = 1, b = 2, c = 'ciao'), z2 = list(a = 0, b = 3, c = 5))
.
revert_list_str_6
排除因为它不支持不同类型的嵌套子元素.
结果:
Unit: microseconds
expr min lq median uq max
1 func_1 249.558 483.2120 502.0915 550.7215 2096.978
2 func_3 210.899 387.6835 400.7055 447.3785 1980.912
3 func_4 92.420 170.9970 182.0335 192.8645 1857.582
4 func_7 257.772 469.9280 477.8795 487.3705 2035.101
Run Code Online (Sandbox Code Playgroud)
获胜者:revert_list_str_4
.
基准3
输入:
list(z1 = list(a = 1, b = m, c = 'ciao'), z2 = list(a = 0, b = 3, c = m))
.
m
是一个整数矩阵3x3,revert_list_str_6
已被排除在外.
结果:
Unit: microseconds
expr min lq median uq max
1 func_1 261.173 484.6345 503.4085 551.6600 2300.750
2 func_3 209.322 393.7235 406.6895 449.7870 2118.252
3 func_4 91.556 174.2685 184.5595 196.2155 1602.983
4 func_7 252.883 474.1735 482.0985 491.9485 2058.306
Run Code Online (Sandbox Code Playgroud)
获胜者:revert_list_str_4
.再次!
结束编辑2.
首先:感谢所有,精彩的解决方案.
在我看来,如果你提前知道你的列表将具有相同名称的嵌套列表,reverse_str_4
那么获胜者就是表演和支持不同类型之间的最佳折衷.
最完整的解决方案是,revert_list_str_7
虽然完全的灵活性导致平均性能的恶化平均约为2.5倍reverse_str_4
(如果您的嵌套列表具有不同的名称,则会很有用).
mne*_*nel 12
问题是do.call rbind没有调用rbind.data.frame
哪个匹配名称.rbind.data.frame
应该工作,因为data.frames是列表,每个子列表都是一个列表,所以我们可以直接调用它.
apply(do.call(rbind.data.frame, z), 1, as.list)
Run Code Online (Sandbox Code Playgroud)
然而,虽然这可能是succicint,但它很慢,因为do.call(rbind.data.frame, ...)
它本身就很慢.
像(分两步)
# convert each component of z to a data.frame
# so rbind.data.frame so named elements are matched
x <- data.frame((do.call(rbind, lapply(z, data.frame))))
# convert each column into an appropriately named list
o <- lapply(as.list(x), function(i,nam) as.list(`names<-`(i, nam)), nam = rownames(x))
o
$a
$a$z1
[1] 1
$a$z2
[1] 1
$b
$b$z1
[1] 2
$b$z2
[1] 4
$c
$c$z1
[1] 3
$c$z2
[1] 0
Run Code Online (Sandbox Code Playgroud)
另一种选择
# unique names
nn <- Reduce(unique,lapply(z, names))
# convert from matrix to list `[` used to ensure correct ordering
as.list(data.frame(do.call(rbind,lapply(z, `[`, nn))))
Run Code Online (Sandbox Code Playgroud)
Jos*_*ien 12
编辑:
这是一个更灵活的版本,可以在列表中使用,这些列表的元素不一定包含同一组子元素.
fun <- function(ll) {
nms <- unique(unlist(lapply(ll, function(X) names(X))))
ll <- lapply(ll, function(X) setNames(X[nms], nms))
ll <- apply(do.call(rbind, ll), 2, as.list)
lapply(ll, function(X) X[!sapply(X, is.null)])
}
## An example of an 'unbalanced' list
z <- list(z1 = list(a = 1, b = 2),
z2 = list(b = 4, a = 1, c = 0))
## Try it out
fun(z)
Run Code Online (Sandbox Code Playgroud)
原始答案
z <- list(z1 = list(a = 1, b = 2, c = 3), z2 = list(b = 4, a = 1, c = 0))
zz <- lapply(z, `[`, names(z[[1]])) ## Get sub-elements in same order
apply(do.call(rbind, zz), 2, as.list) ## Stack and reslice
Run Code Online (Sandbox Code Playgroud)
重塑可以让你靠近,
library(reshape)
b = recast(z, L2~L1)
split(b[,-1], b$L2)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2984 次 |
最近记录: |