проблема
Я хотел бы проверить, существует ли элемент списка, вот пример
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
В этом примере я знаю, что он foo$a
существует, но тест возвращается FALSE
.
Я заглянул ?exists
и обнаружил, что with(foo, exists('a')
возвращается TRUE
, но не понимаю, почему exists('foo$a')
возвращается FALSE
.
Вопросы
- Почему
exists('foo$a')
возвращаетсяFALSE
? - Используется
with(...)
ли предпочтительный подход?
!is.null(foo$a)
(или!is.null(foo[["a"]])
на всякий случай)? (илиexists("a",where=foo)
)foo <- list(a1=1)
Ответы:
На самом деле это немного сложнее, чем вы думаете. Поскольку список может (с некоторыми усилиями) содержать элементы NULL, этого может быть недостаточно для проверки
is.null(foo$a)
. Более строгим тестом может быть проверка того, что имя действительно определено в списке:... и
foo[["a"]]
безопаснееfoo$a
, поскольку последний использует частичное соответствие и, следовательно, может также соответствовать более длинному имени:[ОБНОВЛЕНИЕ] Итак, вернемся к вопросу, почему
exists('foo$a')
не работает.exists
Функция только проверяет , является ли переменным существует в среде, не если части объекта существует. Строка"foo$a"
интерпретируется литературно: существует ли переменная с именем «foo $ a»? ... и ответFALSE
...источник
exists('foo$a') == FALSE
?$mylist[[12]]$out$mcerror
определено), которые в настоящее время были бы чертовски сложными.where
аргументе,exists
указанном в ответе @ Jim ?"bar$a" <- 42
Я действительно хотел бы, чтобы это был недопустимый синтаксис, а exists ("foo $ a") работал в наивном смысле.Лучший способ проверить именованные элементы - использовать
exist()
, однако приведенные выше ответы не используют эту функцию должным образом. Вам нужно использоватьwhere
аргумент, чтобы проверить переменную в списке.источник
exists()
списка действительно работает, но я считаю, что R внутренне принуждает его к среде перед проверкой объекта с таким именем, что неэффективно и может привести к ошибкам, если есть какие-либо неименованные элементы. Например , если вы бежитеexists('a', list(a=1, 2))
, он выдаст сообщение об ошибке:Error in list2env(list(a = 1, 2), NULL, <environment>) : attempt to use zero-length variable name
. Преобразование происходит здесь: github.com/wch/r-source/blob/…Вот сравнение производительности предложенных методов в других ответах.
Если вы планируете использовать список в качестве быстрого словаря, доступ к которому осуществляется много раз, этот
is.null
подход может быть единственным жизнеспособным вариантом. Я предполагаю, что это O (1), а%in%
подход - O (n)?источник
Немного измененная версия @ salient.salamander, если вы хотите проверить полный путь, это можно использовать.
источник
Одно из решений, которое еще не появилось, - это использование length, которое успешно обрабатывает NULL. Насколько я могу судить, все значения, кроме NULL, имеют длину больше 0.
Таким образом, мы могли бы создать простую функцию, которая работает как с именованными, так и с нумерованными индексами:
Если элемент не существует, это вызывает условие выхода за пределы, обнаруженное блоком tryCatch.
источник
rlang::has_name()
тоже могу это сделать:Как видите, он по своей сути обрабатывает все случаи, которые @Tommy показал, как обрабатывать, используя базовый R, и работает для списков с безымянными элементами. Я бы по-прежнему рекомендовал вариант,
exists("bb", where = foo)
предложенный в другом ответе для удобочитаемости, ноhas_name
это альтернатива, если у вас есть безымянные элементы.источник
Используется
purrr::has_element
для проверки значения элемента списка:источник
rapply
(что-то вродеany(rapply(x, function(v) identical(v, c(3, 4)), how = 'unlist'))
)