如何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)?