iterate over list while changing it

T

Torsten Mohr

Hello,

a = [1, 2, 3, 4, 5, 6]

for i, x in enumerate(a):
if x == 3:
a.pop(i)
continue

if x == 4:
a.push(88)

print "i", i, "x", x

I'd like to iterate over a list and change that list while iterating.
I'd still like to work on all items in that list, which is not happening
in the example above.
The conditions in the example are not real but much more complex
in reality.

Can anybody tell me how to do this?


Thanks for any hints,
Torsten.
 
T

Terry Reedy

Torsten said:
Hello,

a = [1, 2, 3, 4, 5, 6]

for i, x in enumerate(a):

If you change a list while iterating over, start at the tail.

....reversed(enumerate(a))

if x == 3:
a.pop(i)

del a # you already have the item
continue

if x == 4:
a.push(88)

no such list method, which mean you did not run the above before
posting. Boo!
 
S

Simon Forman

Hello,

a = [1, 2, 3, 4, 5, 6]

for i, x in enumerate(a):
   if x == 3:
       a.pop(i)
       continue

   if x == 4:
       a.push(88)

   print "i", i, "x", x

I'd like to iterate over a list and change that list while iterating.

This is generally a bad idea, but you can do it if you're careful.

Let's check that enumerate() works when you append to the underlying list:

In [1]: n = range(3)

In [2]: for i, x in enumerate(n):
...: print i, '=>', x
...: if i < 3:
...: n.append(23)
...:
...:
0 => 0
1 => 1
2 => 2
3 => 23
4 => 23
5 => 23

So far so good. But notice if you delete an item from the list while
iterating over the "enumerate object" the index returned will still be
incremented on the next iteration and you'll skip the item after the
one you just deleted:

In [1]: n = range(3)

In [2]: for i, x in enumerate(n):
...: print i, '=>', x, '\t', n
...: if i == 1:
...: del n
...:
...:
0 => 0 [0, 1, 2]
1 => 1 [0, 1, 2]

In [3]: n
Out[3]: [0, 2]

In [4]: n = range(6)

In [5]: for i, x in enumerate(n):
...: print i, '=>', x, '\t', n
...: if i == 3:
...: del n
...:
...:
0 => 0 [0, 1, 2, 3, 4, 5]
1 => 1 [0, 1, 2, 3, 4, 5]
2 => 2 [0, 1, 2, 3, 4, 5]
3 => 3 [0, 1, 2, 3, 4, 5]
4 => 5 [0, 1, 2, 4, 5]


I'd still like to work on all items in that list, which is not happening
in the example above.
The conditions in the example are not real but much more complex
in reality.

Can anybody tell me how to do this?

You could manage the index yourself, like so:

def f(n):
i = 0
while True:
try:
x = n
except IndexError:
break

print i, '=>', x

if x == 3:
del n
continue

if x == 4:
n.append(23)

# Increment the index
# only if you didn't
# delete anything during
# this iteration.
i += 1


N = range(6)
f(N)
print N


This prints:

0 => 0
1 => 1
2 => 2
3 => 3
3 => 4
4 => 5
5 => 23
[0, 1, 2, 4, 5, 23]


HTH,
~Simon
 
A

Aahz

Torsten said:
a = [1, 2, 3, 4, 5, 6]

for i, x in enumerate(a):

If you change a list while iterating over, start at the tail.

This only applies if you add/remove elements; simply updating elements
does not require starting at the tail.
 
Ð

Дамјан ГеоргиевÑки

a = [1, 2, 3, 4, 5, 6]

for i, x in enumerate(a):

If you change a list while iterating over, start at the tail.

...reversed(enumerate(a))

Python 2.6.2 (r262:71600, Jul 20 2009, 02:19:59)
a = [1, 2, 3, 4, 5, 6]
reversed(enumerate(a))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: argument to reversed() must be a sequence
 
S

Simon Forman

a = [1, 2, 3, 4, 5, 6]

for i, x in enumerate(a):
   if x == 3:
       a.pop(i)
       continue

   if x == 4:
       a.push(88)

   print "i", i, "x", x

I'd like to iterate over a list and change that list while iterating.
I'd still like to work on all items in that list, which is not happening
in the example above.

I assume that by "a.push" you meant "a.append".

I believe this will do what you want:

a = [1, 2, 3, 4, 5, 6]
i = 0
while i < len(a):
   x = a
   if x == 3:
       a.pop(i)
       i += 1
       continue

   if x == 4:
       a.append(88)

   print "i", i, "x", x
   i += 1



In the case of x == 3 when you remove an item from the list you should
not increment the index.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top