#r
#r
Вопрос:
Я часто нахожу isset()
from PHP
очень полезным. Пытаясь создать ее R
версию, я пришел к следующему:
isset <- function(x){
a <- try(x, silent = TRUE)
return(!inherits(a, "try-error") amp;amp; !is.null(a) amp;amp; (length(a) != 1L || !is.na(a)))
}
Это сделано с помощью 3 проверок:
- Существует ли объект?
- Если это так, то
NULL
? - Если нет, и не является вектором,
NA
является ли?
Как написано выше isset
, работает очень медленно:
1) Простой случай, вообще нет необходимости в isset
> microbenchmark(isset(NULL), isset(NA))
Unit: microseconds
expr min lq median uq max neval
isset(NULL) 11.867 12.509 12.830 13.310 62.54 100
isset(NA) 12.829 13.471 14.112 14.433 22.45 100
2) Более полезная, но все же выполнимая с помощью is.null()
> test_var <- list(a = 1)
> microbenchmark(isset(test_var$b))
Unit: microseconds
expr min lq median uq max neval
isset(test_var$b) 12.509 13.15 13.791 14.112 112.892 100
3) Здесь это действительно помогает, но также становится очень медленным
> rm(test_var)
> microbenchmark(isset(test_var), isset(test_var$b), try(test_var$b, silent = TRUE))
Unit: microseconds
expr min lq median uq max neval
isset(test_var) 736.038 764.1015 780.4575 815.5755 1223.844 100
isset(test_var$b) 737.001 764.7425 786.0700 815.0940 986.837 100
try(test_var$b, silent = TRUE) 732.832 760.2525 779.3345 815.4155 1034.944 100
Почти все время тратится на try
.
Вопрос: Учитывая, что она должна возвращаться FALSE
в каждом из 3-х приведенных выше случаев, как бы вы переписали, isset
чтобы сделать это как минимум в два раза быстрее?
Ответ №1:
Используйте встроенную exists
:
isset <- function(x) {
is_variable <- make.names(name <- deparse(substitute(x))) == name
if (is_variable amp;amp; !exists(name)) return(FALSE)
!is.null(x) amp;amp; (length(x) != 1L || !is.na(x))
}
# > microbenchmark(isset(test_var), isset(test_var$b))
# Unit: microseconds
# expr min lq median uq max neval
# isset(test_var) 28.011 28.9115 29.278 29.6445 41.960 100
# isset(test_var$b) 47.656 49.1515 49.690 50.4170 137.049 100
Комментарии:
1. Таким образом, она не может определить,
a$b
существует ли. гдеa <- list(b=anything)
.isset(a$b)
выдает FALSE2. лучше и очень быстро, спасибо. Но она завершается с ошибкой, если вы хотите проверить, что
test_var$b
иtest_var
не существует.3. Существует бесконечная перестановка значений такого рода, которая может быть полностью зафиксирована только
tryCatch
и, скорее всего, является проблемой, полной по Тьюрингу. (Например,some_function(a$b[[some_other_function('some_value')]]$etc)
). Если вы ограничиваетесь классом выражений, такихa$b$c
как и т.д. вы можете стать немного лучше,gsub('\$.*', '', name)
сначала.