Jak sprawdzić, czy obiekt (zmienna) jest zdefiniowany w R?

294

Chciałbym sprawdzić, czy jakaś zmienna jest zdefiniowana w R - bez błędu. W jaki sposób mogę to zrobić?

Moje próby (nieudane):

> is.na(ooxx)
Error: object 'ooxx' not found
> is.finite(ooxx)
Error: object 'ooxx' not found

Dzięki!

TMS
źródło

Odpowiedzi:

448

Chcesz exists():

R> exists("somethingUnknown")
[1] FALSE
R> somethingUnknown <- 42
R> exists("somethingUnknown")
[1] TRUE
R> 
Dirk Eddelbuettel
źródło
3
@Gavin i Dirk, jesteście dla siebie tacy mili :) Jedynym rozwiązaniem jest to, że rzucasz monetą (Bernoulli z p = 0,5 :-)), który dostanie akceptację! :-)
TMS
29
@tim, jeśli jesteś w funkcji, brak () jest tym, czego chcesz.
CousinCocaine
2
Sprawdzenie może być nieco trudniejsze, jeśli sprawdzane są elementy listy: stackoverflow.com/q/7719741
TMS
5
co z tego, czego chciał operacja - używając nazwy zmiennej, a nie cudzysłowów?
tim
109

Zobacz ?existsdefinicję „... jest zdefiniowane”. Na przykład

> exists("foo")
[1] FALSE
> foo <- 1:10
> exists("foo")
[1] TRUE
Gavin Simpson
źródło
7
Wygrywasz
9
@DirkEddelbuettel Cóż, jeśli użyjesz śmiesznie długich nazw obiektów ;-)
Gavin Simpson
2
heh Zdarza mi się to przez cały czas, gdy testuję przykłady przed opublikowaniem, Gavin lub Josh już na nie odpowiedzieli.
Maiasaura,
60

jeśli jesteś w funkcji, brak () jest tym, czego chcesz.

exchequer = function(x) {
    if(missing(x)){
        message("x is missing… :-(")
    }
}

exchequer()
x is missing… :-(
tim
źródło
missingdziała jednak tylko dla argumentów funkcji. Nie możesz tego zrobić foo <- function(x) {missing(x); missing(y)}albo dostaniesz foo(1) > Error in missing(y) : 'missing' can only be used for arguments.
Dannid
45

Jak zauważyli inni, szukasz exists. Należy pamiętać, że użycie existsz nazwami używanymi przez pakiety podstawowe R zwróci wartość true niezależnie od tego, czy zmienna została zdefiniowana:

> exists("data")
[1] TRUE

Aby obejść ten problem (jak wskazał Bazz; patrz ?exists), użyj inheritsargumentu:

> exists("data", inherits = FALSE)
[1] FALSE

foo <- TRUE
> exists("foo", inherits = FALSE)
[1] TRUE

Oczywiście, jeśli chcesz przeszukiwać przestrzenie nazw dołączonych pakietów, byłoby to również niewystarczające:

> exists("data.table")
[1] FALSE
require(data.table)
> exists("data.table", inherits = FALSE)
[1] FALSE
> exists("data.table")
[1] TRUE

Jedyne, co mogę wymyślić, aby to obejść - szukać w załączonych pakietach, ale nie w pakietach podstawowych - to:

any(sapply(1:(which(search() == "tools:rstudio") - 1L),
           function(pp) exists(_object_name_, where = pp, inherits = FALSE)))

Porównaj wymianie _object_name_z "data.table"( TRUE) vs "var"( FALSE)

(oczywiście, jeśli nie korzystasz z RStudio, myślę, że pierwszym automatycznie podłączonym środowiskiem jest "package:stats")

sbaldrich
źródło
2
Zabawa, używanie argumentów inherits = FALSEwydaje się izolować rzeczy w globalnym środowisku. Czy to brzmi dobrze?
CJB
1
@Bazz masz rację; Zredagowałem to w odpowiedzi.
MichaelChirico
2
Ten komentarz powinien być wyżej, ponieważ używam nazwy zmiennej „data”, po prostu użycie instrukcji istnienia na początku sprawiło mi pewne problemy.
mzm
25

Jeśli nie chcesz używać cudzysłowów, możesz użyć deparse(substitute())sztuczki, którą znalazłem w przykładowej sekcji ?substitute:

is.defined <- function(sym) {
  sym <- deparse(substitute(sym))
  env <- parent.frame()
  exists(sym, env)
}

is.defined(a)
# FALSE
a <- 10
is.defined(a)
# TRUE
Nirmal
źródło
1
możesz również forcelub ocenić to w funkcji takiej jak ta:is.defined <- function(sym) class(try(sym, TRUE))!='try-error'
chinsoon12
1

Mogą wystąpić sytuacje, w których nie znasz dokładnie nazwy szukanej zmiennej, na przykład gdy tablica wyników została utworzona przez system kolejkowania. Można je rozwiązać za pomocą „ls” i jego argumentu „wzorzec”, który oczekuje wyrażenia regularnego.

Funkcję „istnieje” można ponownie zaimplementować w ten sposób jako

exists <-function(variablename) {
   #print(ls(env=globalenv()))
   return(1==length(ls(pattern=paste("^",variablename,"$",sep=""),env=globalenv())))
}

Przygotowując tę ​​odpowiedź, byłem nieco zaskoczony potrzebą specyfikacji środowiska podczas wywoływania ls () z funkcji. Dziękuję za to, przepełnienie stosu! Istnieje również atrybut „all.names”, który powinienem był ustawić na true, ale go pominąłem.

smoe
źródło