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!

Odpowiedzi:


448

Chcesz exists():

R> exists("somethingUnknown")
[1] FALSE
R> somethingUnknown <- 42
R> exists("somethingUnknown")
[1] TRUE
R> 

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


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… :-(

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")


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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.