tags:

views:

227

answers:

10

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]
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?

+8  A: 

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
ChristopheD
the list2 = [] isn't needed
Peter Gibson
+1  A: 

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.

Ninefingers
+3  A: 

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.
Mark Byers
To downvoter: Reason for downvote? If there is an error in my post, I'd like to know what it is so that I can learn for future.
Mark Byers
+1  A: 

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.

PreludeAndFugue
The second option wouldn't work as you think it will (especially since you want to delete the items of list1)
ChristopheD
@ChristopheD: Sorry, my answer not clear. When I say bind the name list2 to the same object as list1 I was assuming that OP would know that list2 and list1 are both names for the same object.
PreludeAndFugue
@PreludeAndFugue: sorry, i may have misread / misinterpreted your answer then
ChristopheD
@ChristopheD: tried to make answer bit more clear. But so many answers - lot if info to keep OP busy.
PreludeAndFugue
+8  A: 

Hi,

the reason for that is, when you are (appending) and removing from the first list it gets smaller, so you iterator stops before the whole list could walked through.

To achieve what you want, do this:

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

# you could not just make 'list1_copy = list1',
# because this would just copy (share) the reference
# so then when changing list1_copy list1 would 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!

Joschua
And a link to explain list indexing/slicing (`list[:]` is an example of list slicing): http://docs.python.org/tutorial/introduction.html#lists
Wallacoloo
+1  A: 

Try this instead:

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

list2.extend(list1)
list1[:] = []
Shane Holloway
+4  A: 

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.

S.Lott
+2  A: 

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']
Dana
And then list2 would also be `['A', 'B', 'C']`. Question is: why have TWO lists then ;-)
ChristopheD
@ChristopheD: list2 doesn't change - I just checked. A new list object is being created and bound to the name list1, leaving list2 unaffected.
PreludeAndFugue
@PreludeAndFugue: hmm, good point (judged too early without proper thinking)
ChristopheD
Python variables are tricky. Even after working in it for a long time, I still have to occasionally remind myself they are just names pointing at objects in memory.
Dana
+2  A: 

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[:]
Ayman Hourieh
A: 

@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...

Kevin Little