Ответ 1
Как уже отмечалось, vapply
выполняет две вещи:
- Небольшое улучшение скорости
- Улучшает согласованность, предоставляя проверки ограниченного типа возврата.
Второй момент - большее преимущество, поскольку он помогает ловить ошибки до их возникновения и приводит к созданию более надежного кода. Эта проверка возвращаемого значения может быть сделана отдельно с помощью sapply
, за которой следует stopifnot
, чтобы убедиться, что возвращаемые значения соответствуют ожидаемому, но vapply
немного проще (если он более ограничен, так как пользовательский код проверки ошибок может проверять значения в пределах границ и т.д.).
Вот пример vapply
, обеспечивающий ваш результат как ожидалось. Это похоже на то, над чем я только что работал, в то время как PDF-соскабливание, где findD
будет использовать regex, чтобы соответствовать шаблону в необработанных текстовых данных (например, у меня был бы список split
по сущности и регулярное выражение для соответствия адресам внутри каждого объекта. преобразованный вне порядка, и было бы два адреса для сущности, что вызвало нехорошее состояние).
> 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)
## [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
вы гарантированно получите определенный тип вывода, поэтому вам не нужно записывать дополнительные проверки для входов с нулевой длиной.
Бенчмарки
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)