Problem
Ich möchte testen, ob ein Element einer Liste vorhanden ist. Hier ist ein Beispiel
foo <- list(a=1)
exists('foo')
TRUE #foo does exist
exists('foo$a')
FALSE #suggests that foo$a does not exist
foo$a
[1] 1 #but it does exist
In diesem Beispiel weiß ich, dass foo$a
es das gibt, aber der Test kehrt zurück FALSE
.
Ich habe nachgesehen ?exists
und festgestellt, dass es with(foo, exists('a')
zurückkehrt TRUE
, verstehe aber nicht, warum es exists('foo$a')
zurückkehrt FALSE
.
Fragen
- Warum kehrt
exists('foo$a')
zurückFALSE
? - Wird
with(...)
der bevorzugte Ansatz verwendet?
!is.null(foo$a)
(oder!is.null(foo[["a"]])
um auf der sicheren Seite zu sein)? (oderexists("a",where=foo)
)foo <- list(a1=1)
Antworten:
Das ist eigentlich etwas kniffliger als man denkt. Da eine Liste tatsächlich (mit etwas Aufwand) NULL-Elemente enthalten kann, reicht es möglicherweise nicht aus, sie zu überprüfen
is.null(foo$a)
. Ein strengerer Test könnte darin bestehen, zu überprüfen, ob der Name tatsächlich in der Liste definiert ist:... und
foo[["a"]]
ist sicherer alsfoo$a
, da letztere eine teilweise Übereinstimmung verwendet und daher möglicherweise auch mit einem längeren Namen übereinstimmt:[UPDATE] Also zurück zur Frage, warum
exists('foo$a')
nicht funktioniert. Dieexists
Funktion prüft nur, ob eine Variable in einer Umgebung vorhanden ist, nicht, ob Teile eines Objekts vorhanden sind. Die Zeichenfolge"foo$a"
wird literarisch interpretiert: Gibt es eine Variable namens "foo $ a"? ... und die Antwort istFALSE
...quelle
exists('foo$a') == FALSE
?$mylist[[12]]$out$mcerror
definiert ist), die derzeit höllisch kompliziert wären.where
Argument,exists
auf das Sie in der Antwort von @ Jim hingewiesen haben ?"bar$a" <- 42
Ich wünschte wirklich, dies wäre eine ungültige Syntax und existiert ("foo $ a") im naiven Sinne.Der beste Weg, um nach benannten Elementen zu suchen
exist()
, ist die Verwendung . Die obigen Antworten verwenden die Funktion jedoch nicht richtig. Sie müssen daswhere
Argument verwenden, um nach der Variablen in der Liste zu suchen.quelle
exists()
einer Liste funktioniert, aber ich glaube, dass R sie intern in eine Umgebung zwingt, bevor nach einem Objekt dieses Namens gesucht wird. Dies ist ineffizient und kann zu Fehlern führen, wenn unbenannte Elemente vorhanden sind. Wenn Sie beispielsweise ausführenexists('a', list(a=1, 2))
, wird ein Fehler ausgegeben :Error in list2env(list(a = 1, 2), NULL, <environment>) : attempt to use zero-length variable name
. Die Konvertierung erfolgt hier: github.com/wch/r-source/blob/…Hier ist ein Leistungsvergleich der vorgeschlagenen Methoden in anderen Antworten.
Wenn Sie vorhaben, die Liste als schnelles Wörterbuch zu verwenden, auf das häufig zugegriffen wird, ist der
is.null
Ansatz möglicherweise die einzig praktikable Option. Ich nehme an, es ist O (1), während der%in%
Ansatz O (n) ist.quelle
Eine leicht modifizierte Version von @ salient.salamander, wenn man den vollständigen Pfad überprüfen möchte, kann dies verwendet werden.
quelle
Eine Lösung, die noch nicht verfügbar ist, ist die Verwendung von length, die NULL erfolgreich verarbeitet. Soweit ich das beurteilen kann, haben alle Werte außer NULL eine Länge größer als 0.
So könnten wir eine einfache Funktion erstellen, die sowohl mit benannten als auch mit nummerierten Indizes funktioniert:
Wenn das Element nicht vorhanden ist, verursacht es eine Bedingung außerhalb der Grenzen, die vom tryCatch-Block abgefangen wird.
quelle
rlang::has_name()
kann das auch:Wie Sie sehen können, werden von Natur aus alle Fälle behandelt, in denen @Tommy gezeigt hat, wie mit Base R umgegangen wird, und es werden Listen mit unbenannten Elementen verwendet. Ich würde weiterhin empfehlen,
exists("bb", where = foo)
wie in einer anderen Antwort vorgeschlagen, um die Lesbarkeit zu verbessern, aber eshas_name
ist eine Alternative, wenn Sie unbenannte Elemente haben.quelle
Verwenden Sie
purrr::has_element
diese Option , um den Wert eines Listenelements zu überprüfen :quelle
rapply
(so etwas wieany(rapply(x, function(v) identical(v, c(3, 4)), how = 'unlist'))
)