递归purrr :: modify_depth()不适用于参差不齐的列表

时间:2018-02-12 19:56:32

标签: r list recursion tidyverse purrr

说,这是我有点复杂和粗糙的清单:

res <- list(
  a = TRUE,
  b = "error msg 1",
  c = list(
    TRUE,
    "error msg 2"
  ),
  d = list(
    e = "error msg 3",
    "error msg 4",  # no name for this list item just to make things interesting
    f = list(
      g = list(
        h = "error msg 5",
        i = TRUE
      )
    )
  )
)

我现在想要在2 深度(从顶部)应用一些功能。 我的名单可以任意深入和粗糙。

我希望自己都很冷静,所以我会这样做:

purrr::modify_depth(.x = res, .depth = 2, .f = str, .ragged = TRUE)

但是,出乎意料的是,

失败了
Error in .x[] <- .f(.x, ...) : replacement has length zero

不能对此做出正面或反面,因为当我str()手动浏览所有列表元素时,它可以正常工作; str() 总能给出一些结果。

我猜我错了.ragged =

当我使用is.null()作为函数而不是str()时,我也注意到相同的设置有效,但是然后应用于 don't 实际存在(扩展列表)。

purrr::modify_depth(.x = res, .depth = 4, .f = is.null, .ragged = TRUE)

这会创建一个统一 4深的列表,尽管原始版本实际上非常粗糙,只有4个深层 1 分支。

其他未经修改的。

我如何才能n这样做?

1 个答案:

答案 0 :(得分:1)

这是一个古老的问题,但是由于这里缺少令人满意的答案,因此就消失了。

首先,str将输出显示到终端,但实际上不返回任何内容:

is.null(str("anything"))
#>  chr "anything"
#> [1] TRUE

purrr调用失败,因为.f = str试图将NULL的值分配给列表元素,这是不允许的。当前purrr版本(3.4.0)中的错误消息也更清楚地表明了这一点:

purrr::modify_depth(.x = res, .depth = 2, .f = str, .ragged = TRUE)
#>  logi TRUE
#> Error: Result 1 must be a single logical, not NULL of length 0

用其他功能代替strpurrr不再抱怨:

purrr::modify_depth(.x = res, .depth = 2, .f = is.character, .ragged = TRUE)
#> $a
#> [1] FALSE
#> 
#> $b
#> [1] "TRUE"
#> 
#> $c
#> $c[[1]]
#> [1] FALSE
#> 
#> $c[[2]]
#> [1] TRUE
#> 
#> 
#> $d
#> $d$e
#> [1] TRUE
#> 
#> $d[[2]]
#> [1] TRUE
#> 
#> $d$f
#> [1] FALSE

但是,问题仍然存在,modify_depth恰好在.f上应用.depth = 2,因此.f = is.character会将所有更深层次的子列表折叠为逻辑值


purrr程序包(base-rrapply的扩展版本)中,rrapply可能是另一个选项(非rrapply),可以通过嵌套列表进行递归。设置how = "replace",我们只能修改特定深度的元素,而其他所有列表元素均保持不变:

library(rrapply)

rrapply(res, condition = function(x, .xpos) length(.xpos) == 2, f = function(x) paste(x, "<- modified"), how = "replace")
#> $a
#> [1] TRUE
#> 
#> $b
#> [1] "error msg 1"
#> 
#> $c
#> $c[[1]]
#> [1] "TRUE <- modified"
#> 
#> $c[[2]]
#> [1] "error msg 2 <- modified"
#> 
#> 
#> $d
#> $d$e
#> [1] "error msg 3 <- modified"
#> 
#> $d[[2]]
#> [1] "error msg 4 <- modified"
#> 
#> $d$f
#> $d$f$g
#> $d$f$g$h
#> [1] "error msg 5"
#> 
#> $d$f$g$i
#> [1] TRUE

在这里,condition决定将f函数应用于哪些列表元素,而.xpos自变量求值该元素在嵌套列表中的位置作为整数向量。然后length(.xpos)可用于评估嵌套列表中任何元素的深度。