Problème
Je voudrais tester si un élément d'une liste existe, voici un exemple
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
Dans cet exemple, je sais que cela foo$a
existe, mais le test revient FALSE
.
J'ai regardé ?exists
et j'ai trouvé que les with(foo, exists('a')
retours TRUE
, mais je ne comprends pas pourquoi les exists('foo$a')
retours FALSE
.
Des questions
- Pourquoi
exists('foo$a')
revient-ilFALSE
? - L'
with(...)
approche est-elle privilégiée?
!is.null(foo$a)
(ou!is.null(foo[["a"]])
pour être du bon côté)? (ouexists("a",where=foo)
)foo <- list(a1=1)
Réponses:
C'est en fait un peu plus délicat que vous ne le pensez. Puisqu'une liste peut en fait (avec quelques efforts) contenir des éléments NULL, cela peut ne pas être suffisant pour vérifier
is.null(foo$a)
. Un test plus strict pourrait consister à vérifier que le nom est bien défini dans la liste:... et
foo[["a"]]
est plus sûr quefoo$a
, puisque ce dernier utilise une correspondance partielle et peut donc également correspondre à un nom plus long:[MISE À JOUR] Donc, revenons à la question de savoir pourquoi
exists('foo$a')
ne fonctionne pas. Laexists
fonction vérifie uniquement si une variable existe dans un environnement, pas si des parties d'un objet existent. La chaîne"foo$a"
est interprétée littéralement: y a-t-il une variable appelée "foo $ a"? ... et la réponse estFALSE
...la source
exists('foo$a') == FALSE
?$mylist[[12]]$out$mcerror
est défini) qui seraient actuellement compliquées comme l'enfer.where
argumentexists
souligné dans la réponse de @ Jim ?"bar$a" <- 42
Je souhaite vraiment que ce soit une syntaxe invalide et existe ("foo $ a") a fonctionné dans le sens naïf.La meilleure façon de vérifier les éléments nommés est de les utiliser
exist()
, mais les réponses ci-dessus n'utilisent pas correctement la fonction. Vous devez utiliser l'where
argument pour rechercher la variable dans la liste.la source
exists()
sur une liste fonctionne, mais je pense que R la contraint en interne à un environnement avant de rechercher un objet de ce nom, ce qui est inefficace et peut entraîner des erreurs s'il y a des éléments sans nom. Par exemple , si vous exécutezexists('a', list(a=1, 2))
, il vous donnera une erreur:Error in list2env(list(a = 1, 2), NULL, <environment>) : attempt to use zero-length variable name
. La conversion se produit ici: github.com/wch/r-source/blob/…Voici une comparaison des performances des méthodes proposées dans d'autres réponses.
Si vous prévoyez d'utiliser la liste comme un dictionnaire rapide auquel vous avez accédé plusieurs fois, l'
is.null
approche pourrait être la seule option viable. Je suppose que c'est O (1), tandis que l'%in%
approche est O (n)?la source
Une version légèrement modifiée de @ salient.salamander, si l'on veut vérifier le chemin complet, cela peut être utilisé.
la source
Une solution qui n'a pas encore été trouvée consiste à utiliser length, qui gère avec succès NULL. Pour autant que je sache, toutes les valeurs sauf NULL ont une longueur supérieure à 0.
Ainsi, nous pourrions créer une fonction simple qui fonctionne avec les index nommés et numérotés:
Si l'élément n'existe pas, il provoque une condition hors limites interceptée par le bloc tryCatch.
la source
rlang::has_name()
peut faire ça aussi:Comme vous pouvez le voir, il gère intrinsèquement tous les cas que @Tommy a montré comment gérer en utilisant la base R et fonctionne pour les listes avec des éléments sans nom. Je recommanderais toujours
exists("bb", where = foo)
comme proposé dans une autre réponse pour la lisibilité, maishas_name
c'est une alternative si vous avez des éléments sans nom.la source
Utilisez
purrr::has_element
pour vérifier la valeur d'un élément de liste:la source
rapply
(quelque chose commeany(rapply(x, function(v) identical(v, c(3, 4)), how = 'unlist'))
)