2

I am trying to create a function to remove all but one to three items from the global environment. I am able to do it for one but not for two, three or more. Would appreciate any help on this using base R or rlang

a <- "a"
b <- c(1,2,3,4)
c <- c("M", "F")
remove_all_but <- function(x){
  Sx <- deparse(substitute(x))
  rm(list=Sx,envir=sys.frame(-1))
}

remove_all_but(a)

remove_all_but(c(a, b))
#> Warning in rm(list = Sx, envir = sys.frame(-1)): object 'c(a, b)' not found
oguz ismail
  • 1
  • 16
  • 47
  • 69
SimRock
  • 229
  • 3
  • 10

2 Answers2

1

Thanks so much for all of your suggestions. This is really helpful. It gave me some ideas in addition to other things I have also seen in following your links. The following seems to work well.

    remove_all_but <- function(...) {
      names <- as.character(rlang::enexprs(...))
      rm(list=setdiff(ls(pos=1), names), pos=1)
    }
    remove_all_but(a,b)
SimRock
  • 229
  • 3
  • 10
  • Minor suggestion: if you use `rlang::ensyms` instead of `rlang::enxprs`, your function will work with both symbols (`remove_all_but(a,b,c)`) as well as characters (`remove_all_but("a","b","c")`) or any combination of the two. – Artem Sokolov Sep 24 '20 at 19:14
0

A base R solution is:

# assign variables to global environment
a <- 1
b <- 2
c <- 3
d <- 4
e <- 5
ls()
#R> [1] "a" "b" "c" "d" "e"

# make function
remove_all_but <- function(...){
  keep <- sapply(match.call(expand.dots = FALSE)$..., deparse)
  rm(list = setdiff(ls(envir = .GlobalEnv), keep), envir = .GlobalEnv)
}

# use function
remove_all_but(a, b, c)
ls()
#R> [1] "a" "b" "c"

This also work even if remove_all_but is not assigned in the global environment.

You can replace sapply(match.call(expand.dots = FALSE)$..., deparse) with sapply(match.call()[-1], deparse).

We can make this slightly more general by allowing the user select the environment from which variables should be removed from:

# assign variables to an environment
ev <- new.env()
local(envir = ev, {
  a <- 1
  b <- 2
  c <- 3
  d <- 4
  e <- 5
})

ls(envir = ev)
#R> [1] "a" "b" "c" "d" "e"

# make function
remove_all_but <- function(..., envir = .GlobalEnv){
  keep <- sapply(match.call(expand.dots = FALSE)$..., deparse)
  rm(list = setdiff(ls(envir = envir), keep), envir = envir)
}

# use function
remove_all_but(a, b, c, envir = ev)
ls(envir = ev)
#R> [1] "a" "b" "c"