Как уже было отмечено, vapply
выполняет две функции:
- Небольшое улучшение скорости
- Повышает согласованность за счет предоставления ограниченных проверок типа возвращаемого значения.
Второй момент - большее преимущество, так как он помогает выявлять ошибки до того, как они произойдут, и приводит к более надежному коду. Эта проверка возвращаемого значения может выполняться отдельно, используя, sapply
а затем stopifnot
следует, чтобы убедиться, что возвращаемые значения соответствуют ожидаемым, но vapply
это немного проще (если более ограничено, поскольку пользовательский код проверки ошибок может проверять значения в пределах границ и т. Д. ).
Вот пример того, как добиться vapply
ожидаемого результата. Это похоже на то, над чем я только что работал при парсинге PDF, где можно findD
было бы использоватьрегулярное выражениедля соответствия шаблону в необработанных текстовых данных (например, у меня был бы список, split
состоящий из объектов, и регулярное выражение для сопоставления адресов внутри каждого объекта. Иногда 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
Как я говорю своим студентам, часть того, чтобы стать программистом, - это изменить ваше мышление с «ошибки раздражают» на «ошибки - мой друг».
Входы с нулевой длиной.
Один связанный с этим момент заключается в том, что если длина входных данных равна нулю, sapply
всегда будет возвращаться пустой список, независимо от типа ввода. Сравните:
sapply(1:5, identity)
sapply(integer(), identity)
vapply(1:5, identity)
vapply(integer(), identity)
С vapply
, вы гарантированно получите определенный тип вывода, поэтому вам не нужно писать дополнительные проверки для входов нулевой длины.
Контрольные точки
vapply
может быть немного быстрее, потому что он уже знает, в каком формате следует ожидать результатов.
input1.long <- rep(input1,10000)
library(microbenchmark)
m <- microbenchmark(
sapply(input1.long, findD ),
vapply(input1.long, findD, "" )
)
library(ggplot2)
library(taRifx)
autoplot(m)