开发者

iterating through a list removing items, some items are not removed

I'm trying to transfer the contents of one list to another, but it's not working and I don't know why not. My code looks like this:

list1 = [1, 2, 3, 4, 5, 6]
开发者_StackOverflow中文版list2 = []

for item in list1:
    list2.append(item)
    list1.remove(item)

But if I run it my output looks like this:

>>> list1
[2, 4, 6]
>>> list2
[1, 3, 5]

My question is threefold, I guess: Why is this happening, how do I make it work, and am I overlooking an incredibly simple solution like a 'move' statement or something?


The reason is that you're (appending and) removing from the first list whereby it gets smaller. So the iterator stops before the whole list could be walked through.

To achieve what you want, do this:

list1 = [1, 2, 3, 4, 5, 6]
list2 = []

# You couldn't just make 'list1_copy = list1',
# because this would just copy (share) the reference.
# (i.e. when you change list1_copy, list1 will also change)

# this will make a (new) copy of list1
# so you can happily iterate over it ( without anything getting lost :)
list1_copy = list1[:]

for item in list1_copy:
    list2.append(item)
    list1.remove(item)

The list1[start:end:step] is the slicing syntax: when you leave start empty it defaults to 0, when you leave end empty it is the highest possible value. So list1[:] means everything in it. (thanks to Wallacoloo)

Like some dudes said, you could also use the extend-method of the list-object to just copy the one list to another, if this was your intention. (But I choosed the way above, because this is near to your approach.)

As you are new to python, I have something for you: Dive Into Python 3 - it's free and easy. - Have fun!


You're deleting items from list1 while you're iterating over it.

That's asking for trouble.

Try this:

>>> list1 = [1,2,3,4,5,6]
>>> list2 = []
>>> list2 = list1[:] # we copy every element from list1 using a slice
>>> del list1[:] # we delete every element from list1


Essential debugging skill: Add print statements. (or print functions in Python 3)

>>> list1= [1, 2, 3, 4, 5, 6]
>>> for item in list1:
...     print item
...     list1.remove(item)
...     print list1
... 
1
[2, 3, 4, 5, 6]
3
[2, 4, 5, 6]
5
[2, 4, 6]

Notice that Python is trying to step through the positions of the list, but you keep removing items from the list, making the positions become meaningless.

Python picks the item at position 0 from the list.

You then remove the item, changing the list.

Python then picks the item at position 1 from the list (appearing to skip an item)

You then remove that item, changing the list.

Python then picks the item at position 2 from the list (appearing to skip an item)

You then remove the item, changing the list.

Python would then like to pick the item at position 3, but there's no such item. So the loop stops.


You shouldn't modify a list while you iterate over it. This causes the iterator to point at the wrong item. After the first item is handled, the iterator is pointing at index = 1, but because you've removed an item, the next item is now at index zero, so it will be skipped. This is why you are only handling every other item.

Try:

 list2.extend(list1) # This appends all items from list1 to list2.
 del list1[:] # From ChristopheD's post.


Exactly as ChristopheD says.

Could do this:

list1 = [1, 2, 3, 4, 5, 6]
list2 = []

for item in list1:
    list2.append(item)

list1 = []

That'll clear list1.

Edit He/she has updated their post. I'll leave this up as a slight alternative.


Try this instead:

list1 = [1, 2, 3, 4, 5, 6]
list2 = []

list2.extend(list1)
list1[:] = []


There is also the humble copy function (or deepcopy if you have complex objects and not just integers in your list):

from copy import copy

list2 = copy(list1)

You might get a more appropriate answer if you explain what you're trying to accomplish (unless you're just learning about python lists).

"Variables" in Python are just names/references, so the destructive copy you seem to want to do seems kind of strange. If you want list2 to have the same values as list1 you can just do:

list2 = list1 # now they are both referring to the same list

And if after that you want to use list1 for something else, you can just do:

list1 = ['A', 'B', 'C']


Using a list comprehension:

list2 = [item for item in list1]

Bind the name list2 to the the same object as list1:

list2 = list1

(Note that if you modify the contents of list1, list2 will be change accordingly.)

Create a copy of list1 and bind it to the name list2:

list2 = list1[:]

In this case list1 and list2 are different objects.


As you can see in other answers, you are trying to modify the list while iterating over it. This doesn't work. There are many ways to copy one list to another. I did some tests to see how fast each approach is:

>>> timeit.Timer('list2 = list1[:]', 'list1 = range(10**3)').timeit(10**6)
3.9134418964385986

>>> timeit.Timer('list2 = []; list2.extend(list1)', 'list1 = range(10**3)').timeit(10**6)
4.9082601070404053

>>> timeit.Timer('list2 = copy.copy(list1)', 'import copy; list1 = range(10**3)').timeit(10**6)
7.5023419857025146

>>> timeit.Timer('list2 = [i for i in list1]', 'list1 = range(10**3)').timeit(10**6)
95.697894811630249

The slice syntax is the fastest. It's much faster than using a list comprehension.

To clear a list, you can use:

del list1[:]


@potatocubed: Many of the answers given solve the trivial example you gave ("move list1 to list2"), but don't really explain the "why" of the deeper problem, which is modifying a list as you iterate over it. Study S.Lott's answer...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜