2010-03-29 14 views
7

Estoy tratando de transferir el contenido de una lista a otra, pero no está funcionando y no sé por qué no. Mi código es el siguiente:iterando a través de una lista eliminando elementos, algunos elementos no se eliminan

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

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

Pero si lo ejecuto mi producción se ve así:

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

Mi pregunta es triple, supongo: ¿Por qué está sucediendo esto, ¿cómo puedo hacer que funcione , ¿y estoy pasando por alto una solución increíblemente simple como una declaración de 'movimiento' o algo así?

+0

Gracias por toda la ayuda chicos - esa es una explicación concisa y agradable de lo que estaba haciendo mal y varias opciones de reparación, que voy a escabullirme e intentar implementar ahora. =) – potatocubed

Respuesta

8

La razón es que está (añadiendo y) eliminando de la primera lista por la cual se hace más pequeño. Entonces el iterador se detiene antes de que toda la lista pueda ser recorrida.

Para lograr lo que desea, haga lo siguiente:

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) 

El list1[start:end:step] es el slicing syntax: cuando salga de inicio por defecto vacías a 0, cuando salga final vacío es la más alta posible valor. Entonces list1 [:] significa todo en él. (gracias a Wallacoloo)

Como dijeron algunos tipos, también puede usar el extend -metodo del list -objeto para copiar la lista a otra, si esta era su intención. (Pero elegí el camino de arriba, porque esto está cerca de su enfoque.)

Como es nuevo en python, tengo algo para usted: Dive Into Python 3 - es gratis y fácil. - ¡Que te diviertas!

+1

Y un enlace para explicar el indexado/corte de listas ('list [:]' es un ejemplo de rebanado de listas): http://docs.python.org/tutorial/introduction.html#lists – Ponkadoodle

8

Está borrando elementos de list1 mientras está iterando sobre él.

Eso está buscando problemas.

Prueba esto:

>>> 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 
+2

el list2 = [] no es necesario –

1

Exactamente como dice ChristopheD.

podría hacer esto:

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

for item in list1: 
    list2.append(item) 

list1 = [] 

que va a lista1 clara.

Editar Él/ella ha actualizado su post. Dejaré esto como una ligera alternativa.

3

No debe modificar una lista mientras la itera. Esto hace que el iterador apunte al elemento incorrecto. Después de manejar el primer elemento, el iterador apunta al índice = 1, pero debido a que eliminó un elemento, el siguiente elemento ahora está en el índice cero, por lo que se omitirá. Esta es la razón por la que solo manipulas todos los demás artículos.

Probar:

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

Para downvoter: Motivo de downvote? Si hay un error en mi publicación, me gustaría saber de qué se trata para que pueda aprender en el futuro. –

1

Usando una lista por comprensión:

list2 = [item for item in list1] 

Enlazar el nombre list2 al mismo objeto que list1:

list2 = list1 

(Nótese que si se modifica el contenido de list1, list2 será b e cambiará en consecuencia)

Crear una copia de list1 y enlazarlo a nombre list2:.

list2 = list1[:] 

En este caso lista1 y lista2 son diferentes objetos.

+0

La segunda opción no funcionaría como usted cree (especialmente desde que desea eliminar los elementos de list1) – ChristopheD

+0

@ChristopheD: Lo siento, mi respuesta no está clara. Cuando digo unir el nombre list2 al mismo objeto que list1, asumí que OP sabría que list2 y list1 son nombres para el mismo objeto. –

+0

lo siento, es posible que haya leído mal/malinterpretado su respuesta – ChristopheD

1

Tal vez puedas probar:

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

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

habilidad depuración esencial: Añadir print declaraciones. (o print funciones en 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] 

Aviso Python que está tratando de pasar por las posiciones de la lista, pero mantener la eliminación de elementos de la lista, por lo que las posiciones de tener sentido.

Python selecciona el elemento en la posición 0 de la lista.

A continuación, elimina el elemento y cambia la lista.

Python luego toma el tema en la posición 1 de la lista (que aparece a saltar un elemento)

A continuación, se elimine este punto, el cambio de la lista.

Python luego toma el tema en la posición 2 de la lista (que aparece a saltar un elemento)

A continuación, eliminar el elemento, el cambio de la lista.

A Python le gustaría recoger el artículo en la posición 3, pero no hay tal artículo. Entonces el ciclo se detiene.

1

Existe también la función de copia humilde (o DeepCopy si tiene objetos complejos y no sólo los números enteros en su lista):

from copy import copy 

list2 = copy(list1) 

que podría recibir una respuesta más apropiada si se le explica lo que está intentando para lograr (a menos que estés aprendiendo acerca de las listas de Python).

Las "variables" en Python son solo nombres/referencias, por lo que la copia destructiva que parece querer hacer parece extraña.Si quieres lista2 tener los mismos valores que lista1 sólo se puede hacer:

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

Y si después de que desea utilizar lista1 para otra cosa, sólo puede hacer:

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

Y luego list2 también sería ' ['A', 'B', 'C'] '. La pregunta es: ¿por qué tener DOS listas entonces ;-) – ChristopheD

+0

@ChristopheD: list2 no cambia - Acabo de comprobar. Se está creando un nuevo objeto de lista y está vinculado al nombre list1, dejando list2 no afectado. –

+0

@PreludeAndFugue: hmm, buen punto (juzgado demasiado pronto sin el pensamiento adecuado) – ChristopheD

1

Como puede ver en otras respuestas, está tratando de modificar la lista mientras la itera. Esto no funciona Hay muchas maneras de copiar una lista a otra. Hice algunas pruebas para ver qué tan rápido cada enfoque es:

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

La sintaxis del sector es la más rápida. Es mucho más rápido que usar una lista de comprensión.

Para borrar una lista, puede utilizar:

del list1[:] 
0

@potatocubed: Muchas de las respuestas dadas a resolver el ejemplo trivial que diste ("Mover a lista1 Lista2"), pero realmente no explicar el "por qué" del problema más profundo, que está modificando una lista a medida que iteramos sobre ella. Estudie la respuesta de S.Lott ...

Cuestiones relacionadas