max*_*eld 5 recursion r list purrr tidyverse
说,这是我有点复杂和参差不齐的清单:
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
)
)
)
)
Run Code Online (Sandbox Code Playgroud)
我现在想说,在2 深度(从顶部)应用一些函数。我的清单可以任意深入和参差不齐。
我想变得很酷和整洁,所以我认为这会奏效:
purrr::modify_depth(.x = res, .depth = 2, .f = str, .ragged = TRUE)
Run Code Online (Sandbox Code Playgroud)
但是,出乎意料的是,失败了
Error in .x[] <- .f(.x, ...) : replacement has length zero
Run Code Online (Sandbox Code Playgroud)
不能对此做出正面或反面,因为当我str()手动浏览所有列表元素时,它工作得很好;str() 并始终给予一定的结果。
我猜我用.ragged =错了。
我还注意到相同的设置在is.null()用作函数时有效,而不是str(),但随后应用于实际不存在的叶子(扩展列表)。
purrr::modify_depth(.x = res, .depth = 4, .f = is.null, .ragged = TRUE)
Run Code Online (Sandbox Code Playgroud)
这将创建一个统一为4 深的列表,尽管原始实际上相当参差不齐,并且只有 4 深在1 个分支。
什么我喜欢做的,是修改仅适用于那些一个列表元素n的深度确实存在,并给所有的其他修改。
我怎样才能purrr::modify_depth()做到这一点?
这是一个老问题,但由于这里缺少令人满意的答案,所以就这样吧。
首先,str将输出显示到终端,但实际上不返回任何内容:
is.null(str("anything"))
#> chr "anything"
#> [1] TRUE
Run Code Online (Sandbox Code Playgroud)
-调用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
Run Code Online (Sandbox Code Playgroud)
替换str为不同的函数,purrr不再抱怨:
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
Run Code Online (Sandbox Code Playgroud)
然而,问题仍然存在,完全modify_depth适用于因此任何更深层次的子列表都将被折叠成一个逻辑值.f.depth = 2.f = is.character
另一个(非purrr)选项可以位于-package(base- 的扩展版本)rrapply中,以通过嵌套列表进行递归。设置我们只能修改特定深度的元素,同时保持所有其他列表元素不变:rrapplyrrapplyhow = "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
Run Code Online (Sandbox Code Playgroud)
此处,决定将函数应用condition到哪些列表元素,并将参数计算为嵌套列表中元素的位置(作为整数向量)。然后可用于评估嵌套列表中任何元素的深度。f.xposlength(.xpos)