Skip to content Skip to sidebar Skip to footer

Python For Loop List Interesting Result

a = [0,1,2,3,4,5] for b in a: print ':'+str(b) a.pop(0) Thinking that this would work in order going through the entire list and all its items I ran this code and expected thi

Solution 1:

This is completely "expected" and documented behavior. When you iterate over the list, you're basically iterating over memory locations. When you pop something out of the list, everything after that in the list moves 1 index closer to the start of the list. Hence, you end up skipping items. Iteration stops when you reach the end of the list.

Typically when doing something like this, you want to iterate over a copy of the list:

for b in a[:]:
    ...

As indicated in the comments, if you iterate over the list in reversed order:

for b in reversed(a):
    a.pop()

This works as intended because you are constantly pulling off the final element and therefore you're not shifting the position in the list of any of the elements that you haven't yet seen.


Solution 2:

You are looping over a list and altering it at the same time. By using .pop() you are shortening the list, but the iterator pointer is not updated.

Use a copy instead:

for b in list(a):

or

for b in a[:]:

where the [:] slice notation returns a list copy.

Another approach would be to use a while loop instead:

while a:
    print a.pop(0)

because an empty list tests as boolean False.

The python for loop uses it's argument as an iterator, it does not itself keep an index. There is no way for the for loop to 'know' you removed elements. Instead, it's the list() iterator that keeps that pointer:

>>> a = [0,1,2,3,4,5]
>>> itera = iter(a)
>>> itera.next()  # index 0 -> a[0] is 0
0
>>> a.pop(0)
0
>>> a
[1,2,3,4,5]
>>> itera.next()  # index 1 -> a[1] is 2
2

That iterator keeps a counter, and every time you call next() on the iterator it'll give you the value at the next index, whatever that value may be, until the counter is equal to the current lenght of the list.


Solution 3:

If you want to use .pop() in a loop, a common idiom is to use it with while:

a = [0,1,2,3,4,5]
while a:
  print ":{}".format(a.pop(0))

Or, if you want the printed pattern you have there:

a = [0,1,2,3,4,5]
while a:
    print ":{}\n{}".format(a[0],a.pop(0))

prints

:0
0
:1
1
:2
2
:3
3
:4
4
:5
5

Solution 4:

At each iteration of the for loop we have to check the condition b in a So when you start:

a = [0,1,2,3,4,5]
for b in a:
  print ":"+str(b)
  a.pop(0)

b = 0 and in a (meaning elements in a) is 5. Now you print the stringified version of a[b] then remove the first element of the array. Thus iteration two becomes:

a = [1, 2, 3, 4, 5]
b = 1 (it incremented)
size of a = 4 (it shrank)

Next they'll be b=2, size of a becomes 3. The final iteration which would have produced the out of bounds errors you were expecting, won't occur then because b will be larger than the size of the array, so we're done.


Post a Comment for "Python For Loop List Interesting Result"