How to test if list element exists?

前端 未结 7 2018
臣服心动
臣服心动 2020-11-30 21:54

Problem

I would like to test if an element of a list exists, here is an example

foo <- list(a=1)
exists(\'foo\') 
TRUE   #foo does exist
exists(\'         


        
相关标签:
7条回答
  • 2020-11-30 22:33

    rlang::has_name() can do this too:

    foo = list(a = 1, bb = NULL)
    rlang::has_name(foo, "a")  # TRUE
    rlang::has_name(foo, "b")  # FALSE. No partial matching
    rlang::has_name(foo, "bb")  # TRUE. Handles NULL correctly
    rlang::has_name(foo, "c")  # FALSE
    

    As you can see, it inherently handles all the cases that @Tommy showed how to handle using base R and works for lists with unnamed items. I would still recommend exists("bb", where = foo) as proposed in another answer for readability, but has_name is an alternative if you have unnamed items.

    0 讨论(0)
  • 2020-11-30 22:33

    Use purrr::has_element to check against the value of a list element:

    > x <- list(c(1, 2), c(3, 4))
    > purrr::has_element(x, c(3, 4))
    [1] TRUE
    > purrr::has_element(x, c(3, 5))
    [1] FALSE
    
    0 讨论(0)
  • 2020-11-30 22:38

    A slight modified version of @salient.salamander , if one wants to check on full path, this can be used.

    Element_Exists_Check = function( full_index_path ){
      tryCatch({
        len_element = length(full_index_path)
        exists_indicator = ifelse(len_element > 0, T, F)
          return(exists_indicator)
      }, error = function(e) {
        return(F)
      })
    }
    
    0 讨论(0)
  • 2020-11-30 22:41

    Here is a performance comparison of the proposed methods in other answers.

    > 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
    

    If you are planing to use the list as a fast dictionary accessed many times, then the is.null approach might be the only viable option. I assume it is O(1), while the %in% approach is O(n)?

    0 讨论(0)
  • 2020-11-30 22:44

    The best way to check for named elements is to use exist(), however the above answers are not using the function properly. You need to use the where argument to check for the variable within the list.

    foo <- list(a=42, b=NULL)
    
    exists('a', where=foo) #TRUE
    exists('b', where=foo) #TRUE
    exists('c', where=foo) #FALSE
    
    0 讨论(0)
  • 2020-11-30 22:45

    One solution that hasn't come up yet is using length, which successfully handles NULL. As far as I can tell, all values except NULL have a length greater than 0.

    x <- list(4, -1, NULL, NA, Inf, -Inf, NaN, T, x = 0, y = "", z = c(1,2,3))
    lapply(x, function(el) print(length(el)))
    [1] 1
    [1] 1
    [1] 0
    [1] 1
    [1] 1
    [1] 1
    [1] 1
    [1] 1
    [1] 1
    [1] 1
    [1] 3
    

    Thus we could make a simple function that works with both named and numbered indices:

    element.exists <- function(var, element)
    {
      tryCatch({
        if(length(var[[element]]) > -1)
          return(T)
      }, error = function(e) {
        return(F)
      })
    }
    

    If the element doesn't exist, it causes an out-of-bounds condition caught by the tryCatch block.

    0 讨论(0)
提交回复
热议问题