Problema
Me gustaría probar si existe un elemento de una lista, aquí hay un ejemplo
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
En este ejemplo, sé que foo$a
existe, pero la prueba regresa FALSE
.
Busqué ?exists
y encontré que with(foo, exists('a')
regresa TRUE
, pero no entiendo por qué exists('foo$a')
regresa FALSE
.
Preguntas
- ¿Por qué
exists('foo$a')
vuelveFALSE
? - ¿Se utiliza
with(...)
el enfoque preferido?
!is.null(foo$a)
(o!is.null(foo[["a"]])
para estar seguro)? (oexists("a",where=foo)
)foo <- list(a1=1)
Respuestas:
En realidad, esto es un poco más complicado de lo que parece. Dado que una lista en realidad (con algo de esfuerzo) puede contener elementos NULL, puede que no sea suficiente para verificar
is.null(foo$a)
. Una prueba más estricta podría ser verificar que el nombre esté realmente definido en la lista:... y
foo[["a"]]
es más seguro quefoo$a
, ya que este último usa una coincidencia parcial y, por lo tanto, también puede coincidir con un nombre más largo:[ACTUALIZAR] Entonces, volvamos a la pregunta de por qué
exists('foo$a')
no funciona. Laexists
función solo comprueba si existe una variable en un entorno, no si existen partes de un objeto. La cadena"foo$a"
se interpreta literariamente: ¿Existe una variable llamada "foo $ a"? ... y la respuesta esFALSE
...fuente
exists('foo$a') == FALSE
?$mylist[[12]]$out$mcerror
está definido) que actualmente serían muy complicadas.where
argumento que seexists
señaló en la respuesta de @ Jim ?"bar$a" <- 42
Realmente desearía que esto fuera una sintaxis inválida y existiera ("foo $ a") funcionara en el sentido ingenuo.La mejor manera de verificar los elementos con nombre es usar
exist()
, sin embargo, las respuestas anteriores no usan la función correctamente. Necesita usar elwhere
argumento para verificar la variable dentro de la lista.fuente
exists()
en una lista funciona, pero creo que R lo coacciona internamente a un entorno antes de buscar un objeto con ese nombre, lo cual es ineficiente y puede resultar en errores si hay elementos sin nombre. Por ejemplo, si se ejecutaexists('a', list(a=1, 2))
, se le dará un error:Error in list2env(list(a = 1, 2), NULL, <environment>) : attempt to use zero-length variable name
. La conversión ocurre aquí: github.com/wch/r-source/blob/…Aquí hay una comparación de rendimiento de los métodos propuestos en otras respuestas.
Si planea usar la lista como un diccionario rápido al que se accede muchas veces, entonces el
is.null
enfoque podría ser la única opción viable. Supongo que es O (1), mientras que el%in%
enfoque es O (n).fuente
Se puede utilizar una versión ligeramente modificada de @ salient.salamander, si se quiere comprobar la ruta completa.
fuente
Una solución que aún no ha aparecido es el uso de length, que maneja correctamente NULL. Por lo que puedo decir, todos los valores excepto NULL tienen una longitud mayor que 0.
Por lo tanto, podríamos hacer una función simple que funcione con índices numerados y con nombre:
Si el elemento no existe, provoca una condición fuera de límites capturada por el bloque tryCatch.
fuente
rlang::has_name()
también puede hacer esto:Como puede ver, inherentemente maneja todos los casos que @Tommy mostró cómo manejar usando la base R y funciona para listas con elementos sin nombre. Todavía recomendaría
exists("bb", where = foo)
como se propone en otra respuesta para mejorar la legibilidad, perohas_name
es una alternativa si tiene elementos sin nombre.fuente
Úselo
purrr::has_element
para verificar el valor de un elemento de la lista:fuente
rapply
(algo así comoany(rapply(x, function(v) identical(v, c(3, 4)), how = 'unlist'))
)