Make a list of objects that may or may not exist

Viewed 89

Is there an option to build a list from objects, including ones that don't necessarily exist (and thus should simply be ignored)?

Example

my_df <- data.frame(some_values = letters[1:10])
my_vec <- 1:10
my_matrix <- matrix(1:9, nrow = 3, ncol = 3)

list(my_df, my_vec, my_matrix)
#> [[1]]
#>    some_values
#> 1            a
#> 2            b
#> 3            c
#> 4            d
#> 5            e
#> 6            f
#> 7            g
#> 8            h
#> 9            i
#> 10           j
#> 
#> [[2]]
#>  [1]  1  2  3  4  5  6  7  8  9 10
#> 
#> [[3]]
#>      [,1] [,2] [,3]
#> [1,]    1    4    7
#> [2,]    2    5    8
#> [3,]    3    6    9

list(my_df, my_vec, my_matrix, my_object_doesnt_exist)
#> Error in eval(expr, envir, enclos): object 'my_object_doesnt_exist' not found

Created on 2021-01-26 by the reprex package (v0.3.0)

Desired Output

That list(my_df, my_vec, my_matrix, my_object_doesnt_exist) will return the same output as list(my_df, my_vec, my_matrix).

4 Answers

You can use mget and Filter like:

tt <- Filter(Negate(is.null), mget(c("my_df", "my_vec", "my_matrix"
 , "my_object_doesnt_exist"), ifnotfound=list(NULL)))

identical(unname(tt), list(my_df, my_vec, my_matrix))
#[1] TRUE

How about something along the lines of this?

my_df <- data.frame(some_values = letters[1:10])
my_vec <- 1:10
my_matrix <- matrix(1:9, nrow = 3, ncol = 3)

list(my_df, my_vec, my_matrix)
#> [[1]]
#>    some_values
#> 1            a
#> 2            b
#> 3            c
#> 4            d
#> 5            e
#> 6            f
#> 7            g
#> 8            h
#> 9            i
#> 10           j
#> 
#> [[2]]
#>  [1]  1  2  3  4  5  6  7  8  9 10
#> 
#> [[3]]
#>      [,1] [,2] [,3]
#> [1,]    1    4    7
#> [2,]    2    5    8
#> [3,]    3    6    9


res <- lapply(c("my_df", "my_vec", "my_matrix", "my_object_doesnt_exist"),
              function(x) if (exists(x)) get(x) else NA)

res
#> [[1]]
#>    some_values
#> 1            a
#> 2            b
#> 3            c
#> 4            d
#> 5            e
#> 6            f
#> 7            g
#> 8            h
#> 9            i
#> 10           j
#> 
#> [[2]]
#>  [1]  1  2  3  4  5  6  7  8  9 10
#> 
#> [[3]]
#>      [,1] [,2] [,3]
#> [1,]    1    4    7
#> [2,]    2    5    8
#> [3,]    3    6    9
#> 
#> [[4]]
#> [1] NA

# take only non NA values!
res[!is.na(res)]
#> [[1]]
#>    some_values
#> 1            a
#> 2            b
#> 3            c
#> 4            d
#> 5            e
#> 6            f
#> 7            g
#> 8            h
#> 9            i
#> 10           j
#> 
#> [[2]]
#>  [1]  1  2  3  4  5  6  7  8  9 10
#> 
#> [[3]]
#>      [,1] [,2] [,3]
#> [1,]    1    4    7
#> [2,]    2    5    8
#> [3,]    3    6    9

Created on 2021-01-26 by the reprex package (v0.3.0)

With exists():

objects <- c("my_df", "my_vec", "my_matrix", "my_object_doesnt_exist")
mylist <- list()
for (ob in objects) if (exists(ob)) mylist[[ob]] <- get(ob)

Without a for loop:

mget(objects[sapply(objects, exists)])

Using @David nice solution with tidyverse in one call

library(tidyverse)
map(c("my_df", "my_vec", "my_matrix", "my_object_doesnt_exist"),
    function(x) if (exists(x)) get(x) else NA) %>% 
  keep(~ all(!is.na(.x))) 
# [[1]]
#    some_values
# 1            a
# 2            b
# 3            c
# 4            d
# 5            e
# 6            f
# 7            g
# 8            h
# 9            i
# 10           j

# [[2]]
#  [1]  1  2  3  4  5  6  7  8  9 10

# [[3]]
#      [,1] [,2] [,3]
# [1,]    1    4    7
# [2,]    2    5    8
# [3,]    3    6    9
Related