Python: removing a list item during iteration over a list

I repeat the list of elements in Python, do some action on it, and then delete them if they meet certain criteria.

for element in somelist: do_action(element) if check(element): remove_element_from_list 

What should be used instead of remove_element? I saw similar questions, but pay attention to the presence of the do_action part, which must be performed for all elements and, thus, eliminates the decision to use filters.

+67
python list
May 16 '11 at 20:12
source share
9 answers

You can always iterate over a copy of the list, reserve the right to change the original:

 for item in list(somelist): ... somelist.remove(item) 
+113
May 16 '11 at 20:15
source share

To fulfill these criteria: change the original list in place, there are no instances of the list, only one pass, it works , the traditional solution is to iterate backwards:

 for i in xrange(len(somelist) - 1, -1, -1): element = somelist[i] do_action(element) if check(element): del somelist[i] 

Bonus: does not execute len(somelist) at each iteration. Works on any version of Python (at least as far back as 1.5.2) ... s / xrange / range / for 3.X.

Update: if you want to iterate ahead, it's possible, just harder and uglier:

 i = 0 n = len(somelist) while i < n: element = somelist[i] do_action(element) if check(element): del somelist[i] n = n - 1 else: i = i + 1 
+102
May 16 '11 at 23:30
source share

Comp list:

 results = [x for x in (do_action(element) for element in somelist) if check(element)] 
+10
May 16 '11 at 20:20
source share
 for element in somelist: do_action(element) somelist[:] = (x for x in somelist if not check(x)) 

If you really need to do it in one go without copying the list

 i=0 while i < len(somelist): element = somelist[i] do_action(element) if check(element): del somelist[i] else: i+=1 
+7
May 16 '11 at 20:16
source share

You can still use a filter, going to an external function, modifying an element (iterate only once)

 def do_the_magic(x): do_action(x) return check(x) # you can get a different filtered list filter(do_the_magic,yourList) # or have it modified in place (as suggested by Steven Rumbalski, see comment) yourList[:] = itertools.ifilter(do_the_magic, yourList) 
+7
May 16 '11 at 20:20
source share

Another way to do this:

 while i<len(your_list): if #condition : del your_list[i] else: i+=1 

So you remove the elements side by side by checking

+2
Jun 12 '13 at 7:52
source share

You can create a generator that returns everything that has not been deleted:

 def newlist(somelist): for element in somelist: do_action(element) if not check(element): yield element 
+1
May 16 '11 at 20:21
source share

Why not rewrite it as

 for element in somelist: do_action(element) if check(element): remove_element_from_list 

Take a look at this question on how to remove from a list, although it looks like you already saw that Remove items from a list during iteration

Another option is to do this if you really want to keep it the same.

 newlist = [] for element in somelist: do_action(element) if not check(element): newlst.append(element) 
0
May 16 '11 at 20:17
source share

Not quite in place, but there is an idea to do this:

 a = ['a', 'b'] def inplace(a): c = [] while len(a) > 0: e = a.pop(0) if e == 'b': c.append(e) a.extend(c) 

You can expand the function to call the filter in state.

0
Jun 12 '13 at 10:51 on
source share



All Articles