如何对列表中的子列表应用lapply函数

7
假设我有一个列表,其中嵌套着另一个列表,并且我有一些仅适用于向量的函数(如stringr包中的str_replace)。该函数应在实际包含信息的每个元素上执行其工作,这就需要解决以下问题: 问题1:是否有特定的解决方案?
问题2:是否有通用解决方案?
使用循环应该可以解决问题,但这并不优雅,而且可能非常慢 - 在这里效率确实很重要。
让我们看一个例子:
# let's start easy:
test1 <- list(c("a","d"),c("b","d"),c("c","d"))

# does not work:
str_replace(test1,"d","changed")

# but this does:
lapply(test1,str_replace,"d","changed")

# but what now ?
test2 <- list(c(list("a"),"d"),c("b","d"),c("c","d"))

# does not work! :-(
lapply(test2,str_replace,"d","changed")
3个回答

8
这里是如何使用rapply的方法。请注意,rapply的定义中dflthow后面跟着...。因此,我们将参数命名为str_replace:
rapply(test,str_replace,pattern="d",replacement="changed",how='replace')

[[1]]
[[1]][[1]]
[1] "a"

[[1]][[2]]
[1] "changed"


[[2]]
[1] "b"       "changed"

[[3]]
[1] "c"       "changed"

虽然Roland的解决方案涉及更多步骤,但似乎更有效率。 - petermeissner
这个解决方案还能正确处理列表中的空洞(NULL),例如:list(c(list("a"),"d"),c("b","d"),c("c","d"),c(NULL),c("a","d")) - petermeissner

3
您可以使用unlist/relist函数:
library(stringr)
test <- list(c(list("a"),"d"),c("b","d"),c("c","d"))
test2 <- unlist(test)
test2 <- str_replace(test2,"d","changed")
relist(test2,test)

[[1]]
[[1]][[1]]
[1] "a"

[[1]][[2]]
[1] "changed"


[[2]]
[1] "b"       "changed"

[[3]]
[1] "c"       "changed"

我认为这很高效,但尚未经过测试。


尽管这里涉及的步骤比Matthew Lundberg的答案多,但是这个解决方案快了3倍。 - petermeissner
这个解决方案有一个缺陷。如果列表包含空洞(列表的某些部分为NULL值),例如:list(c(list("a"),"d"),c("b","d"),c("c","d"),c(NULL),c("a","d")),它将无法正常工作。请参考Matthew Lundberg的方法以获得一个健壮的解决方案。 - petermeissner
我不认为这是一个缺陷,因为您没有说明列表可以包含空列表(我也看不出为什么应该这样做)。然而,平衡性能与鲁棒性总是需要谨慎处理。 - Roland
当然,在问题中我没有说明这一点 - 没有冒犯的意思。但是,有些人会在意它是否具有鲁棒性(对于我的东西,我确实在意)。这只是额外的信息。 - petermeissner

2

rapply 递归地将函数应用于每个列表元素。你可能需要尝试使用参数 how 来获得正确的输出,但它应该能给你所需的结果。

rapply 的文档在这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接