gpt4 book ai didi

还原列表结构

转载 作者:行者123 更新时间:2023-12-03 12:08:39 24 4
gpt4 key购买 nike

目标

给定一个列表列表,我的目标是反转其结构 (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]]) .我还要指出,它只对 2 个级别的列表起作用,就像报告的那样。

那么,您知道其他更具动态性的解决方案吗?可以 rapply和/或 Filter函数对这个任务有用吗?

结束编辑 1.

建议解决方案的分析

我已经对建议的解决方案进行了一些分析,谢谢大家!
分析包括验证所有功能的以下几点:
  • 接受的类(嵌套列表元素)
  • 如果有不同类型的元素(如果它们是原子的),类型也会保留
  • 包含在保留元素中的对象(例如矩阵)
  • 考虑的列(对于列,我指的是嵌套列表的名称)
  • 不常见的列被忽略( 在这种情况下,分类 'not' 被积极理解 )
  • 保留不常见的列
  • 它也适用于列不匹配(仅基于第一个嵌套列表的名称)

  • 在所有这些情况下 除了第 2.1 点 之外,对分类"is"的理解是肯定的.

    这都是 功能 我已经考虑过( 评论与上面提到的分析项目有关 ):
    # 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)])
    }

    考虑因素

    从这个分析中可以看出:
  • 功能 revert_list_str_7revert_list_str_6最灵活 关于嵌套列表的名称
  • 功能 revert_list_str_4 , revert_list_str_3其次是我自己的功能都够齐全,好取舍。
  • 最全在绝对函数中是 revert_list_str_7 .

  • 基准

    为了完成这项工作,我在这 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 .

    基准 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 .

    基准 3

    输入:
    list(z1 = list(a = 1, b = m, c = 'ciao'), z2 = list(a = 0, b = 3, c = m)) .
    m是一个由整数和 revert_list_str_6 组成的矩阵 3x3又被排除在外了。

    结果:
    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.

    结论

    首先:感谢所有出色的解决方案。

    在我看来,如果您事先知道您的列表将具有相同名称的嵌套列表 reverse_str_4作为性能和对不同类型的支持之间的最佳折衷,是赢家。

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

    最佳答案

    编辑:

    这是一个更灵活的版本,适用于其元素不一定包含相同子元素集的列表。

    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

    关于还原列表结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15263146/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com