Modifying list while iterating

PythonListIteratorLoops

Python Problem Overview


l  = range(100)                         
for i in l:                         
    print i,                         
    print l.pop(0),                  
    print l.pop(0)

The above python code gives the output quite different from expected. I want to loop over items so that I can skip an item while looping.

Please explain.

Python Solutions


Solution 1 - Python

Never alter the container you're looping on, because iterators on that container are not going to be informed of your alterations and, as you've noticed, that's quite likely to produce a very different loop and/or an incorrect one. In normal cases, looping on a copy of the container helps, but in your case it's clear that you don't want that, as the container will be empty after 50 legs of the loop and if you then try popping again you'll get an exception.

What's anything BUT clear is, what behavior are you trying to achieve, if any?! Maybe you can express your desires with a while...?

i = 0
while i < len(some_list):
    print i,                         
    print some_list.pop(0),                  
    print some_list.pop(0)

Solution 2 - Python

I've been bitten before by (someone else's) "clever" code that tries to modify a list while iterating over it. I resolved that I would never do it under any circumstance.

You can use the slice operator mylist[::3] to skip across to every third item in your list.

mylist = [i for i in range(100)]
for i in mylist[::3]:
    print(i)

Other points about my example relate to new syntax in python 3.0.

  • I use a list comprehension to define mylist because it works in Python 3.0 (see below)
  • print is a function in python 3.0

> Python 3.0 range() now behaves like xrange() used to behave, except it works with values of arbitrary size. The latter no longer exists.

Solution 3 - Python

The general rule of thumb is that you don't modify a collection/array/list while iterating over it.

Use a secondary list to store the items you want to act upon and execute that logic in a loop after your initial loop.

Solution 4 - Python

Use a while loop that checks for the truthfulness of the array:

while array:
    value = array.pop(0)
    # do some calculation here

And it should do it without any errors or funny behaviour.

Solution 5 - Python

Try this. It avoids mutating a thing you're iterating across, which is generally a code smell.

for i in xrange(0, 100, 3):
    print i

See xrange.

Solution 6 - Python

I guess this is what you want:

l  = range(100)  
index = 0                       
for i in l:                         
    print i,              
    try:
        print l.pop(index+1),                  
        print l.pop(index+1)
    except IndexError:
        pass
    index += 1

It is quite handy to code when the number of item to be popped is a run time decision. But it runs with very a bad efficiency and the code is hard to maintain.

Solution 7 - Python

This slice syntax makes a copy of the list and does what you want:

l  = range(100)  
for i in l[:]:  
    print i,  
    print l.pop(0),  
    print l.pop(0)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionXolveView Question on Stackoverflow
Solution 1 - PythonAlex MartelliView Answer on Stackoverflow
Solution 2 - PythonEwan ToddView Answer on Stackoverflow
Solution 3 - PythonPaul SasikView Answer on Stackoverflow
Solution 4 - PythonEugene EeoView Answer on Stackoverflow
Solution 5 - PythonHank GayView Answer on Stackoverflow
Solution 6 - PythonYork ChangView Answer on Stackoverflow
Solution 7 - PythonthethinmanView Answer on Stackoverflow