Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R remove objects from a list with if else statement

I have a list of data frames, and would like to remove those with less than 2 rows off from mylist:

a<-data.frame(x=c(1:4),y=c("m", "n", "o", "p"))
b<-data.frame(x=c(2:6),y=c("q", "w", "e", "r", "t"))
c<-data.frame(x=c(6,7),y=c("j","k"),z=c("$","#"))
d<-data.frame(x="9",y="q",z="+")
mylist<-list(a,b,c,d)

for (i in length(mylist)){
if (nrow(mylist[[i]])<=2){
mylist<-mylist[-i]
}
else{
mylist<-myslit
}}

However it only seemed to remove data.frame d. Data frame c is still in "mylist" after running the for loop.

like image 319
lamushidi Avatar asked Apr 23 '13 19:04

lamushidi


People also ask

How do I remove an object from an environment in R?

remove and rm can be used to remove objects. These can be specified successively as character strings, or in the character vector list , or through a combination of both. All objects thus specified will be removed. If envir is NULL then the the currently active environment is searched first.

How do I remove an element from an array in R?

To delete an item at specific index from R Vector, pass the negated index as a vector in square brackets after the vector. We can also delete multiple items from a vector, based on index.


4 Answers

You can do this more easily using an apply loop:

row_lt2 <- which(sapply(mylist, nrow) < 2)
mylist[-row_lt2]
[[1]]
  x y
1 1 m
2 2 n
3 3 o
4 4 p

[[2]]
  x y
1 2 q
2 3 w
3 4 e
4 5 r
5 6 t

[[3]]
  x y z
1 6 j $
2 7 k #

Notice I use negative indexing to remove items instead of selecting them.

like image 98
Paul Hiemstra Avatar answered Sep 28 '22 07:09

Paul Hiemstra


To add to the other answers: this is exactly the type of thing the higher-order Filter function is made for:

> Filter(function(x) {nrow(x) >= 2}, mylist)
[[1]]
  x y
1 1 m
2 2 n
3 3 o
4 4 p

[[2]]
  x y
1 2 q
2 3 w
3 4 e
4 5 r
5 6 t

[[3]]
  x y z
1 6 j $
2 7 k #
like image 45
Jason Morgan Avatar answered Sep 28 '22 06:09

Jason Morgan


You can't do this procedure using for because the indices change. Using for, after removing line 2, you will examine line 3, but you need examine line 2 again (because the line 2 isn't more the same line as before). Change it to repeat or while.

a<-data.frame(x=c(1:4),y=c("m", "n", "o", "p"))
b<-data.frame(x=c(2:6),y=c("q", "w", "e", "r", "t"))
c<-data.frame(x=c(6,7),y=c("j","k"),z=c("$","#"))
d<-data.frame(x="9",y="q",z="+")
mylist<-list(a,b,c,d)

i <- 1
while (i <= length(mylist)) {
 if (nrow(mylist[[i]])<=2){
  mylist<-mylist[-i]
 }
 else{
  i <- i+1
 }
}

Or just use @Paul solution... :P

like image 28
Rcoster Avatar answered Sep 28 '22 06:09

Rcoster


Paul has provided an answer already, but your mistake has not been pointed out.

Your code has two problems. First, you need to supply a range to your loop:

for (i in 1:length(mylist))

or for (i in seq_along(length(mylist)))

Without this, your initialization looked like for (i in 4) after evaluation, meaning that only one iteration was run, removing element 4 and not even looking at all previous elements.

However, if you fix that problem, another one emerges. Namely, your list no longer has 4 elements after removing element 3. It only has 3 elements, while your i index will go up until 4, resulting in subscript out of bounds error.

Therefore one can only suggest the approach using apply, as described by @Paul.

Also, opposed to the assertion otherwise, it is possible to achieve the same using for loop, only your approach needs to be slightly different:

for (i in 1:length(mylist)) {
    if (nrow(mylist[[i]])>2)
    {
        mylist2[i]<-mylist[i]
    }
}  
print(mylist2)

Here you select list elements that are greater than 2, and assign them to a new list. Sapply will be more speedy though.

like image 36
Maxim.K Avatar answered Sep 28 '22 08:09

Maxim.K