如何testing列表元素是否存在?
问题
我想testing一个列表的元素是否存在,这里是一个例子
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
存在,但testing返回FALSE
。
我看着?exists
,并发现with(foo, exists('a')
返回TRUE
,但不明白为什么exists('foo$a')
返回FALSE
。
问题
- 为什么
exists('foo$a')
返回FALSE
? - 使用
with(...)
的首选方法?
这实际上比你想象的要复杂一些。 由于一个列表实际上(有些努力)可以包含NULL元素,所以检查is.null(foo$a)
可能是不够的。 更严格的testing可能是检查名称实际上是在列表中定义的:
foo <- list(a=42, b=NULL) foo is.null(foo[["a"]]) # FALSE is.null(foo[["b"]]) # TRUE, but the element "exists"... is.null(foo[["c"]]) # TRUE "a" %in% names(foo) # TRUE "b" %in% names(foo) # TRUE "c" %in% names(foo) # FALSE
…和foo[["a"]]
比foo$a
更安全,因为后者使用部分匹配,因此也可能匹配更长的名称:
x <- list(abc=4) x$a # 4, since it partially matches abc x[["a"]] # NULL, no match
[更新]所以,回到问题为什么exists('foo$a')
不起作用。 exists
函数只检查一个variables是否存在于一个环境中,而不是一个对象的一部分存在。 string"foo$a"
被解释为literary:是否有一个名为“foo $ a”的variables? …而答案是错误的…
foo <- list(a=42, b=NULL) # variable "foo" with element "a" "bar$a" <- 42 # A variable actually called "bar$a"... ls() # will include "foo" and "bar$a" exists("foo$a") # FALSE exists("bar$a") # TRUE
检查命名元素的最好方法是使用exist()
,但上面的答案没有正确使用该函数。 您需要使用where
参数来检查列表中的variables。
foo <- list(a=42, b=NULL) exists('a', where=foo) #TRUE exists('b', where=foo) #TRUE exists('c', where=foo) #FALSE
以下是在其他答案中提出的方法的性能比较。
> foo <- sapply(letters, function(x){runif(5)}, simplify = FALSE) > microbenchmark::microbenchmark('k' %in% names(foo), is.null(foo[['k']]), exists('k', where = foo)) Unit: nanoseconds expr min lq mean median uq max neval cld "k" %in% names(foo) 467 933 1064.31 934 934 10730 100 a is.null(foo[["k"]]) 0 0 168.50 1 467 3266 100 a exists("k", where = foo) 6532 6998 7940.78 7232 7465 56917 100 b
如果您打算将列表作为多次访问的快速字典,那么is.null
方法可能是唯一可行的select。 我假设它是O(1),而%in%
方法是O(n)?