【问题标题】:Recursive remove NULL elements of list of lists递归删除列表列表的 NULL 元素
【发布时间】:2020-08-03 14:13:41
【问题描述】:

我有一个这样的列表的命名列表:

x <- list(a=1, b=2, c=list(ca=1, cb=2, cc=NULL), d=NULL)

我想删除所有 NULL 元素,包括子列表中的元素。预期结果不包含x$dx$c$cc

我尝试了purrr::compact(x),但它只从顶部列表中删除。 R: removing NULL elements from a list的问题和答案也只适用于顶部列表。

我尝试了rapply(x, purrr::compact),但它没有返回列表。

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    一种方法是在rrapply-package 中使用rrapply(基础rapply 的扩展):

    library(rrapply)
    
    x <- list(a=1, b=2, c=list(ca=1, cb=2, cc=NULL), d=NULL)
    
    rrapply(x, condition = Negate(is.null), how = "prune")
    #> $a
    #> [1] 1
    #> 
    #> $b
    #> [1] 2
    #> 
    #> $c
    #> $c$ca
    #> [1] 1
    #> 
    #> $c$cb
    #> [1] 2
    

    基准时间

    rrapply 的计算时间与 rlist 的 list.clean 函数对一些大型嵌套列表进行基准比较,我得到以下结果:

    ## recursively create nested list with dmax layers and 50% NULL elements
    f <- function(len, d, dmax) {
      x <- vector(mode = "list", length = len)
      for(i in seq_along(x)) {
        if(d + 1 < dmax) {
          x[[i]] <- Recall(len, d + 1, dmax)
        } else {
          x[[i]] <- list(1, NULL)
        }
      }
      return(x)
    }
    
    ## long shallow list (3 layers, total 5e5 nodes)
    x_long <- f(len = 500, d = 1, dmax = 3)
    
    microbenchmark::microbenchmark(
      rlist = rlist::list.clean(x_long, recursive = TRUE),
      rrapply = rrapply::rrapply(x_long, condition = Negate(is.null), how = "prune"),
      check = "equal",
      times = 5L
    )
    #> Unit: milliseconds
    #>     expr       min        lq      mean    median        uq       max neval
    #>    rlist 2331.4914 2343.3001 2438.9674 2441.3850 2512.3484 2566.3121     5
    #>  rrapply  353.7169  393.0646  400.8198  399.7971  417.7235  439.7972     5
    
    ## deeply nested list (18 layers, total 2^18 nodes)
    x_deep <- f(len = 2, d = 1, dmax = 18)
    
    microbenchmark::microbenchmark(
      rlist = rlist::list.clean(x_deep, recursive = TRUE),
      rrapply = rrapply::rrapply(x_deep, condition = Negate(is.null), how = "prune"),
      check = "equal",
      times = 5L
    )
    #> Unit: milliseconds
    #>     expr       min        lq      mean    median        uq       max neval
    #>    rlist 2167.2946 2251.5203 2279.9963 2292.5045 2332.4432 2356.2188     5
    #>  rrapply  268.9463  274.7437  325.9585  292.4559  354.1607  439.4857     5
    

    【讨论】:

      【解决方案2】:

      您可以使用rlist::list.clean(x, recursive = TRUE)。如果您研究源代码,您会看到递归是如何通过一个简单的lapply 循环实现的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-19
        • 2015-06-11
        • 2016-01-05
        • 2011-09-17
        • 2017-09-16
        • 2021-05-29
        • 2015-03-24
        相关资源
        最近更新 更多