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.