Check if object exists in multi-level list at specified path

Viewed 48

I have a multi-level list l with an arbitrary number of levels and entries. To give a simple example:

l <- list(a = 1,
          b = list(x = 2, y = 3),
          c = list(dog = 5, cat = list(fish = 3, mouse = 10))
         )

In my package, the user passes an "address" which specifies an object in this list. The address is passed as a string, of the form:

address = "$c$cat$fish"

This excludes the name of the list itself.

I have written a function which checks whether the address is "valid", in the sense that I want to check whether an object exists at the specified address. The main substance of the function is as follows:

# this is the call to evaluate, as a string
expr_str <- paste0("address_value <- l", address)

# evaluate the call
eval(str2lang(expr_str))

if(is.null(address_value)){
   warning("Address is NULL or not found in list")
}

Now, this works (although there is probably a more elegant way to do it). But the problem is that I get a NOTE in the CMD check because the address_value doesn't have a visible binding, because it is created inside eval().

I want to get rid of the note but I'm not sure how to retrieve whatever is (or isn't) at address without using eval().

Can anyone help with this problem?

2 Answers

Have you considered using purrr::pluck? I think it matches your requirements:

l %>% pluck('c', 'cat', 'fish')
[1] 3

The assignment to address_value can be outside of the eval, which avoids the undeclared variable nag in the CMD check.

check_address <- function(address) {
  
  expr_str <- paste0("l", address)
  
  # evaluate the call
  address_value <- eval(str2lang(expr_str))
  
  if(is.null(address_value)){
    warning("Address is NULL or not found in list")
  }
  
  address_value
}

Which results in:

check_address("$c$cat$fish")
#> [1] 3

check_address("$c$cat$banana")
#> NULL
#> Warning message:
#> In check_address("$c$cat$banana") : Address is NULL or not found in list
Related