943,940 Members | Top Members by Rank

Ad:
  • Python Discussion Thread
  • Unsolved
  • Views: 18128
  • Python RSS
Apr 1st, 2007
0

Removing elements from a list in a loop

Expand Post »
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:

Python Syntax (Toggle Plain Text)
  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
Similar Threads
Reputation Points: 10
Solved Threads: 0
Newbie Poster
Jusa is offline Offline
9 posts
since Mar 2007
Apr 1st, 2007
0

Re: Removing elements from a list in a loop

Hi,

your "error" is a very common source of confusion
Let's take a slightly simpler example:
Python Syntax (Toggle Plain Text)
  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:
Python Syntax (Toggle Plain Text)
  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:
Python Syntax (Toggle Plain Text)
  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:
Python Syntax (Toggle Plain Text)
  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:
Python Syntax (Toggle Plain Text)
  1. lst2 = [ elem for elem in lst if elem != "b" ]

Regards, mawe
Reputation Points: 19
Solved Threads: 58
Junior Poster
mawe is offline Offline
133 posts
since Sep 2005
Apr 2nd, 2007
0

Re: Removing elements from a list in a loop

Thanks for the indepth demonstration. It helped and solved the problem.
Reputation Points: 10
Solved Threads: 0
Newbie Poster
Jusa is offline Offline
9 posts
since Mar 2007
Apr 9th, 2007
0

Re: Removing elements from a list in a loop

Good one, mawe.

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

Python Syntax (Toggle Plain Text)
  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
Reputation Points: 92
Solved Threads: 156
Practically a Master Poster
jrcagle is offline Offline
608 posts
since Jul 2006
Apr 9th, 2007
0

Re: Removing elements from a list in a loop

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:
Python Syntax (Toggle Plain Text)
  1. In [1]: def valid( elem ): # very complicated function
  2. ...: if elem < 0: return False
  3. ...: return True
and then as above
Python Syntax (Toggle Plain Text)
  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
Python Syntax (Toggle Plain Text)
  1. In [4]: filter(valid, lst)
  2. Out[4]: [2, 12]
But as I said, it's just a matter of taste
Reputation Points: 19
Solved Threads: 58
Junior Poster
mawe is offline Offline
133 posts
since Sep 2005
Oct 4th, 2007
0

Re: Removing elements from a list in a loop

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 ?
Reputation Points: 10
Solved Threads: 0
Newbie Poster
pandu22 is offline Offline
1 posts
since Oct 2007

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
Message:
Previous Thread in Python Forum Timeline: need help please
Next Thread in Python Forum Timeline: Graphics help...





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC