В документации говорится
vapply
похож наsapply
, но имеет заранее заданный тип возвращаемого значения, поэтому его [...] может быть безопаснее использовать.
Не могли бы вы пояснить, почему это в целом безопаснее, возможно, приведя примеры?
PS: Я знаю ответ и уже стараюсь избегать sapply
. Я просто хотел бы, чтобы здесь, на SO, был хороший ответ, чтобы я мог указать на него своим коллегам. Пожалуйста, не отвечайте "читать инструкцию".
Ответы:
Как уже было отмечено,
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) ## [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)
источник
Дополнительные нажатия клавиш
vapply
могут сэкономить вам время на отладку запутанных результатов позже. Если вызываемая вами функция может возвращать разные типы данных,vapply
ее обязательно следует использовать.Один пример, который приходит на ум, -
sqlQuery
этоRODBC
упаковка. Если при выполнении запроса произошла ошибка, эта функция возвращаетcharacter
вектор с сообщением. Так, например, предположим, что вы пытаетесь перебрать вектор имен таблицtnames
и выбрать максимальное значение из числового столбца NumCol в каждой таблице с помощью:sapply(tnames, function(tname) sqlQuery(cnxn, paste("SELECT MAX(NumCol) FROM", tname))[[1]])
Если все имена таблиц действительны, это приведет к
numeric
вектору. Но если одно из имен таблиц в базе данных изменится и запрос не будет выполнен, результаты будут переведены в режимcharacter
. Однако использованиеvapply
withFUN.VALUE=numeric(1)
остановит здесь ошибку и предотвратит ее появление где-нибудь в строке - или, что еще хуже, совсем нет.источник
Если вы всегда хотите, чтобы ваш результат был чем-то конкретным ... например, логическим вектором.
vapply
гарантирует, что это произойдет, ноsapply
не обязательно.a<-vapply(NULL, is.factor, FUN.VALUE=logical(1)) b<-sapply(NULL, is.factor) is.logical(a) is.logical(b)
источник
logical(1)
этот случай, поскольку FALSE выглядит так, как будто он устанавливает параметр на «OFF» вместо указания типа