R remove objects from a list with if else statement
Clash Royale CLAN TAG#URR8PPP
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.
5 Answers
5
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.
Thank you so much. It worked out beautifully. :D
– lamushidi
Apr 23 '13 at 19:39
I really love the expressiveness of this functional solution in favor of a more imperative style using a for loop. It is much shorter, in more understandable in my opinion.
– Paul Hiemstra
Apr 23 '13 at 20:18
@PaulHiemstra I agree about the expressiveness of the functional style. This can be made even for succinct with the
Filter
function. (See my answer below.)– Jason Morgan
Apr 23 '13 at 21:04
Filter
To add to the other answers: this is exactly the type of thing the higher-order Filter
function is made for:
Filter
> 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 #
WOW, Filter function is awesome. Thank you!!!
– lamushidi
Apr 23 '13 at 21:30
@lamushidi No problem. Take a look at the other functions available on the same help page as
?Filter
. They can be quite useful.– Jason Morgan
Apr 24 '13 at 0:53
?Filter
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
.
for
for
repeat
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
I just skipped the OP's suggestion, but your are totally right that a for loop is not really useful here.
– Paul Hiemstra
Apr 23 '13 at 19:41
@PaulHiemstra sapply will always be superior, but
for
can be used too, see my answer– Maxim.K
Apr 23 '13 at 19:56
for
Although you take a bit of a different approach than the OP, creating a new one excluding the matches, in stead of deleting the matches from the list.
– Paul Hiemstra
Apr 23 '13 at 20:15
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.
for (i in 4)
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.
i
subscript out of bounds
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
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.
Sapply
+1 nice solution using a
for
loop. If mylist
is big, you could preallocate it first, saving a lot of memory and time.– Paul Hiemstra
Apr 23 '13 at 20:16
for
mylist
@PaulHiemstra I don't see how one could specify the size of mylist2 here, except by using your approach, which renders the whole loop obsolete :)
– Maxim.K
Apr 23 '13 at 20:40
Thanks for pointing out the difference between
(i in length(mylist))
and (i in 1:length(mylist))
. A common mistake I often made.– lamushidi
Apr 23 '13 at 21:35
(i in length(mylist))
(i in 1:length(mylist))
For a few special cases, other methods mentioned above didn't work, although while
could work. I did find that if you use Rcoster's approach while
without adding an evaluation of the returned list, it would still return the wrong answer -- since every time when the condition i<=length(mylist)
got evaluated, the length of mylist
can change, due to the deletion of the mylist[-i]
. Therefore, the while
evaluation could stop before it reaches all unwanted elements in the list.
while
while
i<=length(mylist)
mylist
mylist[-i]
while
For example, in my case, I wanted to make sure all length of mylist[[i]]<=4
. The list is very large (2284879 elements to start with). When the first time I ran the while
evaluation, the program stopped before taking out all mylist[[i]]>4
because the length of mylist
got smaller. I had to use table(lengths(mylist))
to judge whether all unwanted lists were taken out. If not, then run the while
loop again. Luckily it only took two runs. But I thought it is necessary to point it out, in case someone else came here and try to use this while
approach.
mylist[[i]]<=4
while
mylist[[i]]>4
mylist
table(lengths(mylist))
while
while
PS. for
loop should be usable too, if some evaluation added to judge whether re-run is needed.
for
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
+1 for showing what you already tried, and providing a working example.
– Paul Hiemstra
Apr 23 '13 at 19:44