Wie prüfe ich, ob Objekt (Variable) in R definiert ist?

294

Ich möchte überprüfen, ob eine Variable in R definiert ist - ohne einen Fehler zu erhalten. Wie kann ich das machen?

Meine Versuche (nicht erfolgreich):

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

Vielen Dank!

TMS
quelle

Antworten:

448

Sie wollen exists():

R> exists("somethingUnknown")
[1] FALSE
R> somethingUnknown <- 42
R> exists("somethingUnknown")
[1] TRUE
R> 
Dirk Eddelbuettel
quelle
3
@ Gavin & Dirk, du bist so nett zueinander :) Die einzige Lösung ist, dass du die Münze wirfst (Bernoulli mit p = 0,5 :-)), die die Annahme bekommt! :-)
TMS
29
@tim Wenn Sie sich in einer Funktion befinden, möchten Sie () ().
CousinCocaine
2
Könnte
TMS
5
Was ist mit dem, was die Operation wollte - mit dem Variablennamen, nicht in Anführungszeichen?
Tim
109

Siehe ?existsfür eine Definition von "... ist definiert". Z.B

> exists("foo")
[1] FALSE
> foo <- 1:10
> exists("foo")
[1] TRUE
Gavin Simpson
quelle
7
Sie gewinnen mit 52 Sekunden :)
Dirk Eddelbuettel
9
@ KirkEddelbuettel Nun, wenn Sie lächerlich lange Objektnamen verwenden ;-)
Gavin Simpson
2
heh. Passiert mir die ganze Zeit, wenn ich Beispiele vor dem Posten teste, haben Gavin oder Josh bereits darauf geantwortet.
Maiasaura
60

Wenn Sie sich in einer Funktion befinden, möchten Sie (() nicht ().

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

exchequer()
x is missing… :-(
tim
quelle
missingfunktioniert jedoch nur für Funktionsargumente. Sie können nicht tun foo <- function(x) {missing(x); missing(y)}oder Sie werden bekommen foo(1) > Error in missing(y) : 'missing' can only be used for arguments.
Dannid
45

Wie andere betont haben, suchen Sie exists. Beachten Sie, dass die Verwendung existsmit Namen, die von Rs Basispaketen verwendet werden, true zurückgibt, unabhängig davon, ob Sie die Variable definiert haben:

> exists("data")
[1] TRUE

?existsVerwenden Sie das folgende inheritsArgument , um dies zu umgehen (wie von Bazz hervorgehoben; siehe ).

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

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

Wenn Sie die Namensräume angehängter Pakete durchsuchen möchten, ist dies natürlich auch nicht ausreichend:

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

Das einzige, was ich mir vorstellen kann, um dies zu umgehen - in angehängten Paketen zu suchen, aber nicht in Basispaketen - ist das Folgende:

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

Vergleiche Ersetzen _object_name_mit "data.table"( TRUE) vs. "var"( FALSE)

(Wenn Sie nicht auf RStudio sind, ist die erste automatisch angehängte Umgebung natürlich "package:stats")

sbaldrich
quelle
2
Das Herumspielen und Verwenden von Argumenten inherits = FALSEscheint die Dinge in der globalen Umgebung zu isolieren. Klingt das richtig?
CJB
1
@Bazz du bist richtig; Ich habe dies in der Antwort bearbeitet.
MichaelChirico
2
Dieser Kommentar sollte weiter oben stehen, da ich den Variablennamen "data" verwende. Die Verwendung von exist gab mir anfangs einige Probleme.
MZM
25

Wenn Sie keine Anführungszeichen verwenden möchten, können Sie einen deparse(substitute())Trick verwenden, den ich im Beispielabschnitt von ?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
quelle
1
Sie können es auch forceoder in der Funktion wie is.defined <- function(sym) class(try(sym, TRUE))!='try-error'
folgt
1

Es kann Situationen geben, in denen Sie den Namen der gesuchten Variablen nicht genau kennen, z. B. wenn ein Warteschlangensystem eine Reihe von Ergebnissen erstellt hat. Diese können möglicherweise mit "ls" und seinem Argument "pattern" angesprochen werden, das einen regulären Ausdruck erwartet.

Die Funktion "existiert" könnte auf diese Weise wie folgt neu implementiert werden

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

Während ich diese Antwort vorbereitete, war ich ein wenig überrascht über die Notwendigkeit, die Spezifikation der Umgebung zu benötigen, wenn ls () innerhalb einer Funktion aufgerufen wird . Also, danke dafür, Stackoverflow! Es gibt auch ein "all.names" -Attribut, das ich auf true hätte setzen sollen, aber weggelassen habe.

smoe
quelle