为什么“安全”比“安全”更安全?

文件说

vapply类似于sapply ,但具有预先指定的返回值types,因此可以更安全地使用。

请你详细说明为什么它通常更安全,也许提供例子?


PS:我知道答案,我已经倾向于避免sapply 。 我只希望在这里有一个很好的答案,所以我可以指出我的同事。 请不要“阅读手册”的答案。

如前所述, vapply做了两件事:

  • 稍微提高速度
  • 通过提供有限的返回types检查来提高一致性。

第二点是更大的优势,因为它有助于在错误发生之前发现并导致更强大的代码。 这个返回值检查可以通过使用sapplystopifnot单独完成,以确保返回值与您所期望的一致,但vapply更容易一些(如果更有限,由于自定义错误检查代码可以检查边界内的值等)。

这是一个vapply的例子,确保您的结果如预期。 这与我正在处理的东西,而PDF格式的抓取,其中findD将使用正则expression式来匹配原始文本数据中的模式(例如,我有一个由实体split的列表,以及一个匹配每个实体内的地址的正则expression式。偶尔,PDF已经被乱序转换,并且会有一个实体的两个地址,这导致不好)。

 > input1 <- list( letters[1:5], letters[3:12], letters[c(5,2,4,7,1)] ) > input2 <- list( letters[1:5], letters[3:12], letters[c(2,5,4,7,15,4)] ) > findD <- function(x) x[x=="d"] > sapply(input1, findD ) [1] "d" "d" "d" > sapply(input2, findD ) [[1]] [1] "d" [[2]] [1] "d" [[3]] [1] "d" "d" > vapply(input1, findD, "" ) [1] "d" "d" "d" > vapply(input2, findD, "" ) Error in vapply(input2, findD, "") : values must be length 1, but FUN(X[[3]]) result is length 2 

正如我告诉我的学生,成为一名程序员的一部分正在改变你的思想,从“错误是烦人的”到“错误是我的朋友”。

零长度input
一个相关的问题是,如果input长度为零,则无论inputtypes如何, sapply总是会返回一个空列表。 比较:

 sapply(1:5, identity) ## [1] 1 2 3 4 5 sapply(integer(), identity) ## list() vapply(1:5, identity) ## [1] 1 2 3 4 5 vapply(integer(), identity) ## integer(0) 

随着vapply ,你保证有一个特定types的输出,所以你不需要额外的零长度input检查。

基准

vapply可以快一点,因为它已经知道它应该期待的结果是什么格式。

 input1.long <- rep(input1,10000) library(microbenchmark) m <- microbenchmark( sapply(input1.long, findD ), vapply(input1.long, findD, "" ) ) library(ggplot2) library(taRifx) # autoplot.microbenchmark is moving to the microbenchmark package in the next release so this should be unnecessary soon autoplot(m) 

自动绘制

vapply有关的额外的按键可以节省你后来debugging混淆结果的时间。 如果你调用的函数可以返回不同的数据types, vapply一定要使用vapply

一个想到的例子是RODBC包中的RODBC 。 如果执行查询时发生错误,则此函数返回带有消息的character向量。 所以,举个例子,假设你试图迭代一个表名tnames的向量,然后从每个表的数字列'NumCol'中select最大值:

 sapply(tnames, function(tname) sqlQuery(cnxn, paste("SELECT MAX(NumCol) FROM", tname))[[1]]) 

如果所有的表名都是有效的,这将导致一个numeric向量。 但是,如果其中一个表名称在数据库中发生更改并且查询失败,则结果将被强制转换为模式character 。 然而,使用vapplyFUN.VALUE=numeric(1) ,将会阻止这个错误,并防止它popup某处 – 或者更糟的是,根本就不会popup。

如果你总是希望你的结果是特别的东西…例如一个逻辑向量。 vapply确保这种情况发生,但sapply不一定这样做。

 a<-vapply(NULL, is.factor, FUN.VALUE=logical(1)) b<-sapply(NULL, is.factor) is.logical(a) is.logical(b)