15

In Java I can do by using an Iterator and then using the .remove() method of the iterator to remove the last element returned by the iterator, like this:

import java.util.*; public class ConcurrentMod { public static void main(String[] args) { List<String> colors = new ArrayList<String>(Arrays.asList("red", "green", "blue", "purple")); for (Iterator<String> it = colors.iterator(); it.hasNext(); ) { String color = it.next(); System.out.println(color); if (color.equals("green")) it.remove(); } System.out.println("At the end, colors = " + colors); } } /* Outputs: red green blue purple At the end, colors = [red, blue, purple] */ 

How would I do this in Python? I can't modify the list while I iterate over it in a for loop because it causes stuff to be skipped (see here). And there doesn't seem to be an equivalent of the Iterator interface of Java.

2
  • I wonder if using a reverse iterator could be a solution. Any thoughts on this? It would be better than making a copy of a list. Commented Aug 30, 2009 at 2:59
  • stackoverflow.com/questions/1207406/… It gets asked alot ... Commented Aug 30, 2009 at 3:07

4 Answers 4

30

Best approach in Python is to make a new list, ideally in a listcomp, setting it as the [:] of the old one, e.g.:

colors[:] = [c for c in colors if c != 'green'] 

NOT colors = as some answers may suggest -- that only rebinds the name and will eventually leave some references to the old "body" dangling; colors[:] = is MUCH better on all counts;-).

Sign up to request clarification or add additional context in comments.

6 Comments

List comprehension is the best choice.
or colors=list(c for c in colors if c != 'green')
@dugres: not quite: colors = list(...) does rebind. Alex insisted on the idea that it's better not do leave useless lists dangling in memory.
@Devin, NOT just for other references. E.g. if colors is a global doing colors= in a fuction requires an extra global colors, colors[:]= doesn't. GC of the old list does't happen instantly in all versions of Python. Etc: there's NEVER any downside in assigning to name[:], OFTEN many downsides to assigning to name (including the occasional puzzling bug where the "rarely for you" case DOES occur but you're used to the wrong way), so it's a hiding to nothing FOR the correct way, name[:]=, and AGAINST the wrong one, name=. Only one obvious way...
...though it may not be obvious unless you're Dutch;-).
|
25

Iterate over a copy of the list:

for c in colors[:]: if c == 'green': colors.remove(c) 

3 Comments

Why colors[:] instead of colors?
colors[:] is a copy (a weird but, sigh, idiomatic way to spell list(colors)) so it doesn't get affected by the .remove calls.
The only reason to call it more idiomatic is because the stdlib copy module documentation references it. Despite that, I would still use list(otherlist) for copies (or possibly copy.copy(otherthing))
5

You could use filter function:

>>> colors=['red', 'green', 'blue', 'purple'] >>> filter(lambda color: color != 'green', colors) ['red', 'blue', 'purple'] >>> 

Comments

0

or you also can do like this

>>> colors = ['red', 'green', 'blue', 'purple'] >>> if colors.__contains__('green'): ... colors.remove('green') 

3 Comments

There is no advantage in using .__contains__() over 'green' in colors
Plus, colors.remove() only removed the first occurrence instead of all the occurrences.
The solution could be made to work, via: while 'green' in colors: colors.remove('green') . Of course, this is O(n**2), while the better solutions are O(n).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.