Установлена R-версия функции PHP

#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) выдает FALSE

2. лучше и очень быстро, спасибо. Но она завершается с ошибкой, если вы хотите проверить, что test_var$b и test_var не существует.

3. Существует бесконечная перестановка значений такого рода, которая может быть полностью зафиксирована только tryCatch и, скорее всего, является проблемой, полной по Тьюрингу. (Например, some_function(a$b[[some_other_function('some_value')]]$etc) ). Если вы ограничиваетесь классом выражений, таких a$b$c как и т.д. вы можете стать немного лучше, gsub('\$.*', '', name) сначала.