Como ya se ha señalado, vapply
hace dos cosas:
- Mejora leve de la velocidad
- Mejora la coherencia al proporcionar comprobaciones de tipo de devolución limitadas.
El segundo punto es la mayor ventaja, ya que ayuda a detectar errores antes de que sucedan y conduce a un código más robusto. Esta verificación del valor de retorno se puede hacer por separado usando sapply
seguido de stopifnot
para asegurarse de que los valores de retorno sean consistentes con lo que esperaba, pero vapply
es un poco más fácil (si es más limitado, ya que el código de verificación de errores personalizado podría verificar valores dentro de los límites, etc. ).
Este es un ejemplo de vapply
cómo garantizar que su resultado sea el esperado. Esto es paralelo a algo en lo que estaba trabajando mientras raspaba PDF, donde findD
usaría unregexpara hacer coincidir un patrón en los datos de texto sin procesar (por ejemplo, tendría una lista split
por entidad y una expresión regular para hacer coincidir las direcciones dentro de cada entidad. Ocasionalmente, el PDF se había convertido fuera de orden y habría dos direcciones para un entidad, que causó maldad).
> 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
Como les digo a mis alumnos, parte de convertirse en programador es cambiar su forma de pensar de "los errores son molestos" a "los errores son mi amigo".
Entradas de longitud cero
Un punto relacionado es que si la longitud de entrada es cero, sapply
siempre devolverá una lista vacía, independientemente del tipo de entrada. Comparar:
sapply(1:5, identity)
sapply(integer(), identity)
vapply(1:5, identity)
vapply(integer(), identity)
Con vapply
, tiene la garantía de tener un tipo particular de salida, por lo que no necesita escribir comprobaciones adicionales para entradas de longitud cero.
Benchmarks
vapply
puede ser un poco más rápido porque ya sabe en qué formato debería esperar los resultados.
input1.long <- rep(input1,10000)
library(microbenchmark)
m <- microbenchmark(
sapply(input1.long, findD ),
vapply(input1.long, findD, "" )
)
library(ggplot2)
library(taRifx)
autoplot(m)