Removing elements from a list in a loop

Reply

Join Date: Mar 2007
Posts: 9
Reputation: Jusa is an unknown quantity at this point 
Solved Threads: 0
Jusa Jusa is offline Offline
Newbie Poster

Removing elements from a list in a loop

 
0
  #1
Apr 1st, 2007
Hi,

I'm having trouble removing objects from a list. It seems that when I remove single objects in a loop, the loop kind of skips elements in the list, not continuing from the point where the last removal occurred. I want to remove only certain elements from a list, and there should be a way for an object of the list to remove itself, or mark itself for removal.

Example code:

  1. class FooObj:
  2. def __init__(self, i, a):
  3. self.i = i
  4. self.a = a
  5.  
  6. def rem(self, list): #Doesn't work correctly
  7. list.remove(self)
  8.  
  9. def __repr__(self):
  10. return "(obj " + str(self.i) + ", active = " + str(self.a) + ")"
  11.  
  12.  
  13. if __name__ == "__main__":
  14. o1 = FooObj(1, 1)
  15. o2 = FooObj(2, 0)
  16. o3 = FooObj(3, 0)
  17. o4 = FooObj(4, 1)
  18. o5 = FooObj(5, 1)
  19.  
  20. #Test 1
  21. lst = [o1, o2, o3, o4, o5]
  22.  
  23. #Trying to remove objects flagged as inactive (a = 0)
  24. for obj in lst:
  25. if obj.a == 0:
  26. lst.remove(obj)
  27.  
  28. #Prints: [(obj 1, active = 1), (obj 3, active = 0), (obj 4, active = 1), (obj 5, active = 1)]
  29. #^obj 3 is wrong! All objs with a=0 should be removed.
  30. print lst
  31.  
  32.  
  33. #Test 2
  34. lst = [o1, o2, o3, o4, o5]
  35.  
  36. #Trying to remove all objects. I need to be able to call a function of the object for each object in the loop.
  37. for obj in lst:
  38. obj.rem(lst)
  39.  
  40. #Prints: [(obj 2, active = 0), (obj 4, active = 1)]
  41. #completely wrong
  42. print lst



-Jusa
Reply With Quote Quick reply to this message  
Join Date: Sep 2005
Posts: 133
Reputation: mawe is an unknown quantity at this point 
Solved Threads: 58
mawe mawe is offline Offline
Junior Poster

Re: Removing elements from a list in a loop

 
0
  #2
Apr 1st, 2007
Hi,

your "error" is a very common source of confusion
Let's take a slightly simpler example:
  1. In [1]: lst = ["a", "b", "b", "d"]
  2.  
  3. In [2]: for elem in lst:
  4. ....: print "before: ", lst # check the list
  5. ....: print elem, lst.index(elem) # check which element we are using
  6. ....: if elem == "b": # remove if element is a "b"
  7. ....: lst.remove(elem)
  8. ....: print "after: ", lst # check list again
  9. ....: print "-" * 20
  10. ....:
  11. before: ['a', 'b', 'b', 'd']
  12. a 0
  13. after: ['a', 'b', 'b', 'd']
  14. --------------------
  15. before: ['a', 'b', 'b', 'd']
  16. b 1
  17. after: ['a', 'b', 'd']
  18. --------------------
  19. before: ['a', 'b', 'd']
  20. d 2
  21. after: ['a', 'b', 'd']
  22. --------------------
Ok, let's go through the output step by step:
  1. before: ['a', 'b', 'b', 'd']
  2. a 0
  3. after: ['a', 'b', 'b', 'd']
The first element in our list as an "a", it has the index 0 (the first index). It's not a "b" so we don't remove it and our list looks the same as before. Step 2:
  1. before: ['a', 'b', 'b', 'd']
  2. b 1
  3. after: ['a', 'b', 'd']
Yeah, some action here! We are checking element number 2, with index 1, and it's a b -> remove it. Our list has now 3 elements ... alarm bells ringing? Let's look at Step 3:
  1. before: ['a', 'b', 'd']
  2. d 2
  3. after: ['a', 'b', 'd']
See what happened? There is still a "b" here, but it is the second element, index 1. We already did something with the second element, in step 2. Now we are checking element number 3. It's a "d", so it stays and ... the loop is finished. Because we deleted one element, we jumped over one "b".
Thats what happens in your code.

What did we learn: Never delete something from or add something to the list you are iterating over.

The solution is: iterate over your original list, and put everything which passes your test into another list:
  1. lst2 = [ elem for elem in lst if elem != "b" ]

Regards, mawe
Reply With Quote Quick reply to this message  
Join Date: Mar 2007
Posts: 9
Reputation: Jusa is an unknown quantity at this point 
Solved Threads: 0
Jusa Jusa is offline Offline
Newbie Poster

Re: Removing elements from a list in a loop

 
0
  #3
Apr 2nd, 2007
Thanks for the indepth demonstration. It helped and solved the problem.
Reply With Quote Quick reply to this message  
Join Date: Jul 2006
Posts: 608
Reputation: jrcagle is on a distinguished road 
Solved Threads: 150
jrcagle jrcagle is offline Offline
Practically a Master Poster

Re: Removing elements from a list in a loop

 
0
  #4
Apr 9th, 2007
Good one, mawe.

If you need to filter the list in a more complicated way, you can also do this:

  1. for item in mylist[:]:
  2. if item_is_a_reject(): #whatever test you need to run goes here
  3. mylist.remove(item)

so we iterate through a *copy* of mylist, but remove items from the original.

Jeff
Reply With Quote Quick reply to this message  
Join Date: Sep 2005
Posts: 133
Reputation: mawe is an unknown quantity at this point 
Solved Threads: 58
mawe mawe is offline Offline
Junior Poster

Re: Removing elements from a list in a loop

 
0
  #5
Apr 9th, 2007
You are right, that's another way. It may be a matter of taste, but ... I don't like it I would rather do something like this:
  1. In [1]: def valid( elem ): # very complicated function
  2. ...: if elem < 0: return False
  3. ...: return True
and then as above
  1. In [2]: lst = [-3, 2, -5, -10, 12]
  2. In [3]: [ elem for elem in lst if valid(elem) ]
  3. Out[3]: [2, 12]
or, because I'm a big fan of functional programming
  1. In [4]: filter(valid, lst)
  2. Out[4]: [2, 12]
But as I said, it's just a matter of taste
Reply With Quote Quick reply to this message  
Join Date: Oct 2007
Posts: 1
Reputation: pandu22 is an unknown quantity at this point 
Solved Threads: 0
pandu22 pandu22 is offline Offline
Newbie Poster

Re: Removing elements from a list in a loop

 
0
  #6
Oct 4th, 2007
1. Implement the linked list program with the Vectors concepts that you have learnt.
2. Take 1 Vector and store all the values in it.
3. Take another vector and store the addresses of the next value (in this context it would be the indexes of the first vector).
4. So far Example, If you want to insert an element at the end, insert it to the end of the first vector and store its index in the second vector.
5. Similarly, If you want to insert an element in the beginning of the list:
1. Insert the value at the end of the first array.
2. Now, Shuffle all the addresses in the second Vector appropriately.
6. Please click here for the example document.
I want coding for these 6 ?
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC