Remove Environment (and List) elements based on your classes

5

Consider the vectors:

a<-1:10
b<-1:10
c<-'a'
d<-'a'
e<-list('b')
f<-list('b')
g<-1.1
h<-1.1

The function below removes only a class (which is integer , in this case):

rm(list=names(Filter(is.integer,mget(ls()))))

I have tried to modify this function (eg to use some operators inside it so that it was possible to enter two or more classes) but until now I have not been able to do this.

Two questions:

  • How to remove more than one class (such as integer and list ) and leave the others in the environment ?

asked by anonymous 01.01.2019 / 05:09

3 answers

5

Based on this answer , you can also do this (in a more " tidyverse ):

library(purrr)

remover <- ls() %>% 
  map(get) %>% 
  map(class) %>% 
  map_lgl(~.x %in% c("list",  "integer")) %>% 
  keep(.x = ls(envir = .GlobalEnv))

rm(list = remover)

ls()
# [1] "c" "d" "g" "h"

The functions get and ls have a envir argument to know "where" to perform the search. You can pass a list to this argument to make the list version.

    
02.01.2019 / 14:31
5

Call an anonymous function within rm() to not affect objects displayed in ls() .

a<-1:10
b<-1:10
c<-'a'
d<-'a'
e<-list('b')
f<-list('b')
g<-1.1
h<-1.1

rm(list = (function(x, types){

  envType <- sapply(x, function(x) {
    typeof(get(x)) # retorna um vetor (nomeado com o nome de cada objeto em ls()) com o tipo de cada objeto em ls()
  })

  out <- names(which(sapply(envType, function(x){
    any(x %in% types)
  }) == TRUE)) # retorna um vetor com os nomes dos objetos que obedecem a condição em "types".

  return(out)

})(ls(), c("list", "integer")) # observe que o argumento "type" é flexível
)

What returns:

> ls()
[1] "c" "d" "g" "h"
    
01.01.2019 / 06:07
5

One option is to use the is() function that is more generic than is.integer , for example. It requires, as the second argument the class to be checked.

Placing the result of the mget(ls()) proposed in the question within a list can be useful in avoiding to be recreating the list at each iteration of the function.

ambiente <- mget(ls())

So we could have a function that returns the name of the objects of a list that are of certain class.

filtrar_classe <- function(classe, lista) {
  names(Filter(function(x) is(x, classe), lista))
}

Once the function is defined, we can apply it to the desired classes

classes <- c("list",  "integer") 

res <- classes %>% 
  lapply(filtrar_classe, lista = ambiente) %>% 
  unlist()
res
# [1] "e" "f" "a" "b"

Now that we have a vector of characters as an answer, we can pass its result as argument to the function rm() .

rm(list = res)
ls()
# [1] "ambiente"       "c"              "classes"        "d"             
# [5] "filtrar_classe" "g"              "h"              "res" 

tidyverse

If we want to leave the solution more "tidy", we can do as follows

filtrar_tidy <- function(classe, lista) {
  keep(lista, ~ is(.x, classe)) %>% 
    names()
}

classes %>% 
  map(filtrar_tidy, lista = ambiente) %>% 
  flatten_chr()

About the option in the list

The idea is the same, just use the names together with [ to select the elements of the list you want to delete.

nova_lista <- ambiente[ !names(ambiente) %in% res ]
nova_lista
$c
[1] "a"   
$d
[1] "a"    
$g
[1] 1.1    
$h
[1] 1.1
    
02.01.2019 / 03:58