Problema
Eu gostaria de testar se existe um elemento de uma lista, aqui está um exemplo
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
Neste exemplo, sei que foo$a
existe, mas o teste retorna FALSE
.
Procurei ?exists
e descobri que with(foo, exists('a')
retorna TRUE
, mas não entendo por que exists('foo$a')
retorna FALSE
.
Questões
- Por que
exists('foo$a')
retornaFALSE
? - É o uso da
with(...)
abordagem preferida?
!is.null(foo$a)
(ou!is.null(foo[["a"]])
para estar no lado seguro)? (ouexists("a",where=foo)
)foo <- list(a1=1)
Respostas:
Na verdade, isso é um pouco mais complicado do que você pensa. Como uma lista pode realmente (com algum esforço) conter elementos NULL, pode não ser o suficiente para verificar
is.null(foo$a)
. Um teste mais rigoroso pode ser verificar se o nome está realmente definido na lista:... e
foo[["a"]]
é mais seguro do quefoo$a
, uma vez que o último usa correspondência parcial e, portanto, também pode corresponder a um nome mais longo:[ATUALIZAÇÃO] Então, de volta à pergunta por
exists('foo$a')
que não funciona. Aexists
função verifica apenas se uma variável existe em um ambiente, não se existem partes de um objeto. A string"foo$a"
é interpretada literariamente: existe uma variável chamada "foo $ a"? ... e a resposta éFALSE
...fonte
exists('foo$a') == FALSE
?$mylist[[12]]$out$mcerror
está definido) que atualmente seriam complicadas como o inferno.where
argumentoexists
apontado na resposta de @Jim ?"bar$a" <- 42
Eu realmente gostaria que essa sintaxe fosse inválida e existisse ("foo $ a") funcionasse no sentido ingênuo.A melhor maneira de verificar os elementos nomeados é usar
exist()
, no entanto, as respostas acima não estão usando a função corretamente. Você precisa usar owhere
argumento para verificar a variável na lista.fonte
exists()
em uma lista funciona, mas acredito que R coage internamente para um ambiente antes de verificar um objeto com esse nome, o que é ineficiente e pode resultar em erros se houver algum elemento sem nome. Por exemplo, se você executarexists('a', list(a=1, 2))
, ele irá dar um erro:Error in list2env(list(a = 1, 2), NULL, <environment>) : attempt to use zero-length variable name
. A conversão acontece aqui: github.com/wch/r-source/blob/...Aqui está uma comparação de desempenho dos métodos propostos em outras respostas.
Se você planeja usar a lista como um dicionário rápido acessado muitas vezes, então a
is.null
abordagem pode ser a única opção viável. Presumo que seja O (1), enquanto a%in%
abordagem é O (n)?fonte
Uma versão ligeiramente modificada de @ saliente.salamander, se alguém quiser verificar o caminho completo, pode ser usada.
fonte
Uma solução que ainda não surgiu é usar length, que lida com NULL com sucesso. Pelo que eu posso dizer, todos os valores, exceto NULL, têm um comprimento maior que 0.
Assim, poderíamos fazer uma função simples que funcione com índices nomeados e numerados:
Se o elemento não existir, ele causará uma condição fora dos limites capturada pelo bloco tryCatch.
fonte
rlang::has_name()
pode fazer isso também:Como você pode ver, ele trata de maneira inerente todos os casos que @Tommy mostrou como tratar usando a base R e funciona para listas com itens não nomeados. Eu ainda recomendaria
exists("bb", where = foo)
como proposto em outra resposta para facilitar a leitura, mashas_name
é uma alternativa se você tiver itens sem nome.fonte
Use
purrr::has_element
para verificar o valor de um elemento da lista:fonte
rapply
(algo comoany(rapply(x, function(v) identical(v, c(3, 4)), how = 'unlist'))
)