首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >还原列表结构

还原列表结构
EN

Stack Overflow用户
提问于 2013-03-07 12:34:42
回答 6查看 4.1K关注 0票数 23

目标

给出一个列表,我的目标是颠倒它的结构 (R )。

因此,我希望将嵌套列表的元素作为第一层列表的元素。

也许一个例子能更好地说明我的目的。给定:

z <- list(z1 = list(a = 1, b = 2, c = 3), z2 = list(b = 4, a = 1, c = 0))

我想要一个等同于后续R对象的输出:

o <- list(a = list(z1 = 1, z2 = 1), b = list(z1 = 2, z2 = 4), c = list(z1 = 3, z2 = 0))

解决方案

我的解决方案

我创建了自己的解决方案,我将其附加在下面,但如果有更好的解决方案,请告诉我。

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
}

执行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

但是,正如我所说的,我想调查(并了解)是否存在一个更优雅、更动态的解决方案。

事实上,只有当所有嵌套列表都具有相同的名称(顺序也不同)时,我的解决方案才能完全工作。这要归功于names(ls[[1]])。我还想指出的是,它只在两个级别的列表上起作用,就像上面报道的那样。

那么,你知道其他更有活力的解决方案吗?rapply和/或Filter函数对此任务是否有用?

结束编辑1。

对建议的解决方案进行分析

我已经对提议的解决方案做了一点分析,谢谢你们!分析包括验证所有功能的以下几点:

如果存在不同类型的元素(如果它们是保留的元素(例如matrix) )中包含的atomic)

  • object ),也会保留
  1. 接受的类(嵌套列表元素)
    1. 类型

考虑的列(对于列,我指的是嵌套列表的名称)未保留的公共列被忽略(在本case)

  • not
    1. 中,分类‘
    2. ’被明确理解为‘’它也适用于列不匹配的情况(仅基于第一个嵌套列的名称

在所有这种情况下,除了2.1点之外,分类'yes‘被积极理解。

这是我考虑过的所有函数(注释与上面提到的分析项相关):

# 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)])
}

注意事项

从这个分析中可以看出:

关于嵌套list

  • functions代码的名称,代码函数revert_list_str_7revert_list_str_6是最灵活的代码,代码加上我自己的函数已经足够完整了,good trade-offs.

  • the 在绝对函数中最完整的<代码>E258>是< revert_list_str_4 >D59revert_list_str_3 >。

基准测试

为了完成这项工作,我对这4个函数做了一些小的基准测试(使用microbenchmark 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

赢家:revert_list_str_4

BENCHMARK 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

赢家:revert_list_str_4

BENCHMARK 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

赢家:revert_list_str_4。再来一次!

结束编辑2。

结论

首先:感谢所有精彩的解决方案。

在我看来,如果你事先知道你的list会有同名的嵌套列表,那么reverse_str_4就是赢家,因为它在性能和对不同类型的支持之间取得了最佳的折衷。

最完整的解决方案是revert_list_str_7,尽管与reverse_str_4相比,完全的灵活性平均会导致大约2.5倍的性能恶化(如果嵌套列表具有不同的名称,则很有用)。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2013-03-07 13:25:23

编辑:

这里有一个更灵活的版本,它将在元素不一定包含相同的子元素集的列表上工作。

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)

原始答案

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
票数 13
EN

Stack Overflow用户

发布于 2013-03-07 12:53:44

编辑--来自@Josh O‘’Briens的建议和我自己的改进

问题是do.call rbind没有调用rbind.data.frame,它会进行一些名称匹配。rbind.data.frame应该可以工作,因为data.frames是列表,每个子列表都是一个列表,所以我们可以直接调用它。

apply(do.call(rbind.data.frame, z), 1, as.list)

然而,虽然这可能是成功的,但它很慢,因为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

和另一种选择

# 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))))
票数 12
EN

Stack Overflow用户

发布于 2013-03-07 14:01:34

重塑可以拉近你的距离,

library(reshape)
b = recast(z, L2~L1)
split(b[,-1], b$L2)
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15263146

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档