Reputation: 587
I'm trying to go through a list, which is growing during the loop. For larger lists, I encounter a strange behavior, the iteration stops before going through all elements:
from blist import sortedlist
# for-loop
l = sortedlist(range(400))
for x in l:
print(x)
if x % 10 == 0:
l.add(max(l) + 1)
print('last element:', l[-1])
# while-loop
l = sortedlist(range(400))
k = 0
while True:
try:
print(l[k])
if l[k] % 10 == 0:
l.add(max(l) + 1)
k = k + 1
except IndexError:
break
print('last element:', l[-1])
Results:
.
.
.
430
431
last element: 443
.
.
.
443
444
last element: 444
This does not occur for a normal list. And the "while-loop" goes through all elements as I want. I suppose sortedlist
are stored as trees structures, and somehow it does not play well with modifiying a list during a loop, but if anyone has more insight on this (and/or a clearer/better way to get the same behavior than the "while-loop")
Note that it is not a critical portion performant-wise, so I don't mind the log(n) access cost in the "while-loop" case.
Upvotes: 0
Views: 1188
Reputation: 877
The reason is very simple. When you create a foreach loop over a collection, the loop retains a local copy of the information of the list it iterates through. This means it only iterates the length of your original lists (with no regards to any modifications).
The while loop just checks whether a condition is true for each iteration and does not keep a local copy of your list information.
Based on your comment I tried to reproduce it but was unsuccessful. However this seem to produce what you want:
l = sorted(range(400))
for x in l:
print x
if x%10 == 0:
l.append(max(l)+1)
print str(l[-1])
Upvotes: 2