Pregunta

Estoy iterando sobre una lista de tuplas en Python y estoy intentando eliminarlas si cumplen con ciertos criterios.

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

¿Qué debo usar en lugar de code_to_remove_tup ? No puedo averiguar cómo eliminar el elemento de esta manera.

¿Fue útil?

Solución

Puede utilizar una lista de comprensión para crear una nueva lista que contenga solo los elementos que no desea eliminar:

somelist = [x for x in somelist if not determine(x)]

O, al asignar a la porción somelist [:] , puede mutar la lista existente para que contenga solo los elementos que desee:

somelist[:] = [x for x in somelist if not determine(x)]

Este enfoque podría ser útil si hay otras referencias a somelist que deben reflejar los cambios.

En lugar de una comprensión, también puede usar itertools . En Python 2:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

O en Python 3:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

Otros consejos

Las respuestas que sugieren la comprensión de la lista son CASI correctas, excepto que crean una lista completamente nueva y luego le dan el mismo nombre a la lista anterior, NO modifican la lista anterior en su lugar. Eso es diferente de lo que harías por una eliminación selectiva, como en la sugerencia de @Lennart : es más rápido, pero si tu se accede a la lista a través de varias referencias; el hecho de que solo estés volviendo a colocar una de las referencias y NO alteres el objeto de la lista en sí puede dar lugar a errores sutiles y desastrosos.

Afortunadamente, es extremadamente fácil obtener tanto la velocidad de comprensión de la lista como la semántica requerida de la modificación in situ, solo el código:

somelist[:] = [tup for tup in somelist if determine(tup)]

Observe la sutil diferencia con otras respuestas: esta NO se asigna a un nombre de barra: se asigna a una porción de la lista que resulta ser la lista completa, por lo que se reemplaza la lista contenidos dentro del mismo objeto de lista de Python , en lugar de simplemente volver a colocar una referencia (del objeto de lista anterior al nuevo objeto de lista) como las otras respuestas.

Debes tomar una copia de la lista e iterarla primero, o la iteración fallará con resultados inesperados.

Por ejemplo (depende de qué tipo de lista):

for tup in somelist[:]:
    etc....

Un ejemplo:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]
for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

Necesitas ir hacia atrás, de lo contrario es como aserrar la rama de árbol en la que estás sentado :-)

Usuarios de Python 2: reemplaza range por xrange para evitar crear una lista codificada

Su mejor enfoque para este ejemplo sería un comprensión de la lista

somelist = [tup for tup in somelist if determine(tup)]

En los casos en los que estás haciendo algo más complejo que llamar a una función determine , prefiero crear una nueva lista y simplemente agregarla a medida que avanzo. Por ejemplo

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

Copiar la lista usando remove puede hacer que su código se vea un poco más limpio, como se describe en una de las respuestas a continuación. Definitivamente no debería hacer esto para listas extremadamente grandes, ya que esto implica copiar primero la lista completa y también realizar una operación O (n) remove para cada elemento que se esté eliminando, haciendo de esto un algoritmo O (n ^ 2) .

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

Tutorial oficial de Python 2 4.2. " para Declaraciones "

https://docs.python.org/2/tutorial /controlflow.html#for-statements

Esta parte de los documentos deja claro que:

  • necesita hacer una copia de la lista iterada para modificarla
  • una forma de hacerlo es con la notación de segmento ?:?
  

Si necesita modificar la secuencia sobre la que está iterando mientras está dentro del bucle (por ejemplo, para duplicar elementos seleccionados), se recomienda que primero haga una copia. Iterar sobre una secuencia no hace una copia implícitamente. La notación de división hace que esto sea especialmente conveniente:

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

Documentación de Python 2 7.3. " La declaración '"

https://docs.python.org/2/reference/compound_stmts .html # para

Esta parte de la documentación dice una vez más que tienes que hacer una copia, y da un ejemplo de eliminación real:

  

Nota: hay una sutileza cuando la secuencia está siendo modificada por el bucle (esto solo puede ocurrir para secuencias mutables, es decir, listas). Se utiliza un contador interno para realizar un seguimiento de qué elemento se utiliza a continuación, y esto se incrementa en cada iteración. Cuando este contador ha alcanzado la longitud de la secuencia, el bucle termina. Esto significa que si la suite elimina el elemento actual (o uno anterior) de la secuencia, se omitirá el siguiente elemento (ya que obtiene el índice del elemento actual que ya se ha tratado). Del mismo modo, si la suite inserta un elemento en la secuencia anterior al elemento actual, el elemento actual se tratará nuevamente la próxima vez a través del bucle. Esto puede llevar a errores desagradables que pueden evitarse haciendo una copia temporal utilizando una porción de toda la secuencia, por ejemplo,

for x in a[:]:
    if x < 0: a.remove(x)

Sin embargo, no estoy de acuerdo con esta implementación, ya que .remove () tiene que iterar la lista completa para encontrar el valor.

En su lugar, ya sea:

Por lo general, solo desea optar por la opción más rápida de .append () a menos que la memoria sea una gran preocupación.

¿Python podría hacer esto mejor?

Parece que esta API de Python en particular podría mejorarse. Compárelo, por ejemplo, con su homólogo de Java ListIterator , lo que deja en claro que no puede modificar una lista que se está iterando excepto con el propio iterador, y le brinda formas eficientes de hacerlo sin copiar la lista.

Quizás la razón subyacente es que se supone que las listas de Python están respaldadas por arreglos dinámicos, y por lo tanto, cualquier tipo de eliminación será ineficiente en el tiempo de todos modos, mientras que Java tiene una jerarquía de interfaz más agradable con ambos ArrayList y LinkedList implementaciones de ListIterator .

Tampoco parece haber un tipo de lista vinculada explícita en la presentación estándar de Python: Lista enlazada de Python

Para aquellos que les gusta la programación funcional:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

o

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

También podría ser inteligente crear una nueva lista si el elemento de la lista actual cumple con los criterios deseados.

entonces:

for item in originalList:
   if (item != badValue):
        newList.append(item)

y para evitar tener que volver a codificar todo el proyecto con el nuevo nombre de las listas:

originalList[:] = newList

nota, de la documentación de Python:

  

copia.copia (x)   Devuelva una copia superficial de x.

     

copy.deepcopy (x)   Devuelve una copia profunda de x.

Necesitaba hacer esto con una lista enorme, y duplicar la lista me pareció costosa, especialmente porque en mi caso la cantidad de eliminaciones sería muy baja en comparación con los elementos que quedan. Tomé este enfoque de bajo nivel.

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

Lo que no sé es qué tan eficientes se comparan un par de eliminaciones con copiar una lista grande. Por favor comente si tiene alguna idea.

Esta respuesta fue escrita originalmente en respuesta a una pregunta que desde entonces ha sido marcada como duplicada: Eliminación de coordenadas de la lista en python

Hay dos problemas en tu código:

1) Al usar remove (), intentas eliminar enteros mientras que necesitas eliminar una tupla.

2) El bucle for omitirá los elementos de tu lista.

Analicemos lo que sucede cuando ejecutamos su código:

>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
...   if a < 0 or b < 0:
...     L1.remove(a,b)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)

El primer problema es que está pasando tanto 'a' como 'b' a remove (), pero remove () solo acepta un único argumento. Entonces, ¿cómo podemos hacer que remove () funcione correctamente con su lista? Necesitamos averiguar qué es cada elemento de tu lista. En este caso, cada uno es una tupla. Para ver esto, accedamos a un elemento de la lista (la indexación comienza en 0):

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>

¡Ajá! Cada elemento de L1 es en realidad una tupla. Así que eso es lo que tenemos que pasar para eliminar (). Las tuplas en python son muy fáciles, se hacen simplemente encerrando valores entre paréntesis. " a, b " no es una tupla, pero " (a, b) " es una tupla Así que modificamos tu código y lo ejecutamos de nuevo:

# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))

Este código se ejecuta sin ningún error, pero veamos la lista que produce:

L1 is now: [(1, 2), (5, 6), (1, -2)]

¿Por qué (1, -2) todavía está en tu lista? Resulta que modificar la lista mientras se usa un bucle para recorrerla es una muy mala idea sin un cuidado especial. La razón por la que (1, -2) permanece en la lista es que las ubicaciones de cada elemento dentro de la lista cambiaron entre las iteraciones del bucle for. Veamos qué sucede si alimentamos el código anterior con una lista más larga:

L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

Como puede inferir de ese resultado, cada vez que la sentencia condicional se evalúe como verdadera y se elimine un elemento de la lista, la siguiente iteración del bucle omitirá la evaluación del siguiente elemento en la lista porque sus valores ahora se encuentran en diferentes índices.

La solución más intuitiva es copiar la lista, luego iterar sobre la lista original y solo modificar la copia. Puedes intentar hacerlo así:

L2 = L1
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)

Sin embargo, la salida será idéntica a la anterior:

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

Esto se debe a que cuando creamos L2, Python no creó realmente un nuevo objeto. En su lugar, simplemente hizo referencia a L2 con el mismo objeto que L1. Podemos verificar esto con 'es', que es diferente de simplemente " igual a " (==).

>>> L2=L1
>>> L1 is L2
True

Podemos hacer una copia verdadera usando copy.copy (). Entonces todo funciona como se espera:

import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

Finalmente, hay una solución más limpia que tener que hacer una copia completamente nueva de L1. La función invertida ():

L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
    if a < 0 or b < 0 :
        L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

Desafortunadamente, no puedo describir adecuadamente cómo funciona reversed (). Devuelve un objeto 'listreverseiterator' cuando se le pasa una lista. Por motivos prácticos, puede pensar que se trata de una copia invertida de su argumento. Esta es la solución que recomiendo.

Si desea hacer algo más durante la iteración, puede ser bueno obtener tanto el índice (lo que garantiza que pueda hacer referencia a él, por ejemplo, si tiene una lista de dictados) como el contenido real del elemento de la lista.

inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]    
for idx, i in enumerate(inlist):
    do some stuff with i['field1']
    if somecondition:
        xlist.append(idx)
for i in reversed(xlist): del inlist[i]

enumerar le da acceso al elemento y al índice de una vez. revertido es para que los índices que luego elimines no cambien en ti.

Es posible que desee utilizar filter () disponible como integrado.

Para más detalles marque aquí

Puedes intentar hacer bucles inversos, por lo que para some_list harás algo como:

list_len = len(some_list)
for i in range(list_len):
    reverse_i = list_len - 1 - i
    cur = some_list[reverse_i]

    # some logic with cur element

    if some_condition:
        some_list.pop(reverse_i)

De esta manera, el índice se alinea y no sufre las actualizaciones de la lista (independientemente de si se selecciona o no el elemento cur).

Una posible solución, útil si desea no solo eliminar algunas cosas, sino también hacer algo con todos los elementos en un solo bucle:

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1

La mayoría de las respuestas aquí quieren que crees una copia de la lista. Tuve un caso de uso donde la lista era bastante larga (110K elementos) y era más inteligente seguir reduciendo la lista en su lugar.

En primer lugar, deberás reemplazar el bucle foreach with por el bucle while ,

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

El valor de i no se cambia en el bloque if porque querrá obtener el valor del nuevo elemento DESDE EL MISMO ÍNDICE, una vez que se elimine el elemento anterior.

Necesitaba hacer algo similar y, en mi caso, el problema era la memoria: necesitaba unir múltiples objetos de conjunto de datos dentro de una lista, después de hacer algunas cosas con ellos, como un nuevo objeto, y necesitaba deshacerme de cada entrada. se estaba fusionando para evitar duplicarlos y hacer explotar la memoria. En mi caso, tener los objetos en un diccionario en lugar de una lista funcionó bien:

`` `

k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}

print d
for i in range(5):
    print d[i]
    d.pop(i)
print d

`` `

TLDR:

Escribí una biblioteca que te permite hacer esto:

from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)  
for tup in fSomeList:
    if determine(tup):
        # remove 'tup' without "breaking" the iteration
        fSomeList.remove(tup)
        # tup has also been removed from 'someList'
        # as well as 'fSomeList'

Si es posible, es mejor usar otro método que no requiera modificar su iterable mientras se itera sobre él, pero para algunos algoritmos puede que no sea tan sencillo. Y así, si está seguro de que realmente desea el patrón de código descrito en la pregunta original, es posible.

Debería funcionar en todas las secuencias mutables, no solo en las listas.


Respuesta completa:

Editar: el último ejemplo de código en esta respuesta proporciona un caso de uso para por qué a veces es posible que desee modificar una lista en lugar de usar una lista de comprensión. La primera parte de las respuestas sirve como tutorial de how una matriz se puede modificar en su lugar.

La solución sigue desde esta respuesta (para una pregunta relacionada) del remitente. Lo que explica cómo se actualiza el índice de matriz al iterar a través de una lista que se ha modificado. La solución a continuación está diseñada para rastrear correctamente el índice de matriz, incluso si se modifica la lista.

Descargue fluidIter.py de aquí https: / /github.com/alanbacon/FluidIterator , es solo un archivo único, por lo que no es necesario instalar git. No hay un instalador, por lo que deberá asegurarse de que el archivo se encuentre en la ruta de Python. El código se ha escrito para python 3 y no se ha probado en python 2.

from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]  
fluidL = FluidIterable(l)                       
for i in fluidL:
    print('initial state of list on this iteration: ' + str(fluidL)) 
    print('current iteration value: ' + str(i))
    print('popped value: ' + str(fluidL.pop(2)))
    print(' ')

print('Final List Value: ' + str(l))

Esto producirá el siguiente resultado:

initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2

initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3

initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4

initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5

initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6

initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7

initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8

Final List Value: [0, 1]

Anteriormente, hemos utilizado el método pop en el objeto de lista fluida. También se implementan otros métodos comunes, como del fluidL [i] , .remove , .insert , .append , .extend . La lista también se puede modificar utilizando segmentos (no se implementan los métodos sort y reverse ).

La única condición es que solo debe modificar la lista en su lugar, si en algún punto fluidL o l se reasignó a un objeto de lista diferente, el código no funcionaría . El objeto original fluidL aún sería utilizado por el bucle for, pero quedaría fuera del alcance para que lo modifiquemos.

es decir,

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

Si queremos acceder al valor de índice actual de la lista, no podemos utilizar enumerar, ya que esto solo cuenta cuántas veces se ha ejecutado el bucle for. En su lugar, utilizaremos el objeto iterador directamente.

fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
    print('enum: ', i)
    print('current val: ', v)
    print('current ind: ', fluidArrIter.currentIndex)
    print(fluidArr)
    fluidArr.insert(0,'a')
    print(' ')

print('Final List Value: ' + str(fluidArr))

Esto dará como resultado lo siguiente:

enum:  0
current val:  0
current ind:  0
[0, 1, 2, 3]

enum:  1
current val:  1
current ind:  2
['a', 0, 1, 2, 3]

enum:  2
current val:  2
current ind:  4
['a', 'a', 0, 1, 2, 3]

enum:  3
current val:  3
current ind:  6
['a', 'a', 'a', 0, 1, 2, 3]

Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]

La clase FluidIterable solo proporciona una envoltura para el objeto de lista original. Se puede acceder al objeto original como una propiedad del objeto fluido, de este modo:

originalList = fluidArr.fixedIterable
Puede encontrar más ejemplos / pruebas en la sección si __name__ es " __ main __ " ;: en la parte inferior de fluidIter.py . Vale la pena mirarlos porque explican lo que sucede en diversas situaciones. Tales como: Reemplazar grandes secciones de la lista usando un sector. O usando (y modificando) el mismo iterable en anidados para bucles.

Como dije antes: esta es una solución complicada que perjudicará la legibilidad de su código y hará que sea más difícil de depurar. Por lo tanto, se deben considerar primero otras soluciones, como la lista de comprensión mencionada en la respuesta de David Raznick. Dicho esto, he encontrado momentos en los que esta clase me ha sido útil y me ha resultado más fácil de usar que hacer un seguimiento de los índices de los elementos que deben eliminarse.


Editar: Como se mencionó en los comentarios, esta respuesta no presenta realmente un problema para el cual este enfoque proporciona una solución. Intentaré abordar esto aquí:

Las comprensiones de listas proporcionan una forma de generar una nueva lista, pero estos enfoques tienden a ver cada elemento de forma aislada en lugar del estado actual de la lista en su conjunto.

es decir,

newList = [i for i in oldList if testFunc(i)]

Pero, ¿qué sucede si el resultado de testFunc depende de los elementos que ya se agregaron a newList ? ¿O los elementos que aún están en oldList que podrían agregarse a continuación? Puede que aún haya una forma de utilizar una lista de comprensión, pero comenzará a perder su elegancia, y para mí es más fácil modificar una lista en su lugar.

El siguiente código es un ejemplo de un algoritmo que sufre el problema anterior. El algoritmo reducirá una lista para que ningún elemento sea un múltiplo de cualquier otro elemento.

randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
    print(' ')
    print('outer val: ', i)
    innerIntsIter = fRandInts.__iter__()
    for j in innerIntsIter:
        innerIndex = innerIntsIter.currentIndex
        # skip the element that the outloop is currently on
        # because we don't want to test a value against itself
        if not innerIndex == fRandIntsIter.currentIndex:
            # if the test element, j, is a multiple 
            # of the reference element, i, then remove 'j'
            if j%i == 0:
                print('remove val: ', j)
                # remove element in place, without breaking the
                # iteration of either loop
                del fRandInts[innerIndex]
            # end if multiple, then remove
        # end if not the same value as outer loop
    # end inner loop
# end outerloop

print('')
print('final list: ', randInts)

La salida y la lista reducida final se muestran a continuación

outer val:  70

outer val:  20
remove val:  80

outer val:  61

outer val:  54

outer val:  18
remove val:  54
remove val:  18

outer val:  7
remove val:  70

outer val:  55

outer val:  9
remove val:  18

final list:  [20, 61, 7, 55, 9]

Las otras respuestas son correctas, por lo general es una mala idea eliminar de una lista que estás iterando. La iteración inversa evita las trampas, pero es mucho más difícil seguir el código que hace eso, por lo que generalmente es mejor usar una lista de comprensión o filter .

Sin embargo, hay un caso en el que es seguro eliminar elementos de una secuencia que está iterando: si solo está eliminando un elemento mientras está iterando. Esto se puede asegurar usando un return o un break . Por ejemplo:

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

A menudo, esto es más fácil de entender que una comprensión de lista cuando realiza algunas operaciones con efectos secundarios en el primer elemento de una lista que cumple con alguna condición y luego lo elimina de la lista inmediatamente después.

El método más efectivo es la comprensión de listas, muchas personas muestran su caso, por supuesto, también es una buena manera de obtener un iterator a través de filter .

  

Filter recibe una función y una secuencia. Filter aplica la función pasada a cada elemento, y luego decide si retiene o descarta el elemento dependiendo de si el valor de retorno de la función es True o False .

Hay un ejemplo (obtener las probabilidades en la tupla):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

Precaución: tampoco puede manejar iteradores. Los iteradores a veces son mejores que las secuencias.

Puedo pensar en tres enfoques para resolver tu problema. Como ejemplo, crearé una lista aleatoria de tuplas somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)] . La condición que elijo es suma de elementos de una tupla = 15 . En la lista final solo tendremos aquellas tuplas cuya suma no sea igual a 15.

Lo que he elegido es un ejemplo elegido al azar. No dudes en cambiar la lista de tuplas y la condición que he elegido.

Método 1. > Use el marco que sugirió (donde se rellena un código dentro de un bucle for). Uso un pequeño código con del para eliminar una tupla que cumple con dicha condición. Sin embargo, este método perderá una tupla (que satisface dicha condición) si dos tuplas colocadas consecutivamente cumplen con la condición dada.

for tup in somelist:
    if ( sum(tup)==15 ): 
        del somelist[somelist.index(tup)]

print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]

Método 2. > Construya una nueva lista que contenga elementos (tuplas) donde no se cumpla la condición dada (esto es lo mismo que eliminar elementos de la lista donde se cumple la condición dada) . El siguiente es el código para eso:

newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]

print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

Método 3. > Encuentre índices en los que se cumple la condición dada, y luego use eliminar elementos (tuplas) correspondientes a esos índices. El siguiente es el código para eso.

indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]

print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

El método 1 y el método 2 son más rápidos que el método 3 . Method2 y method3 son más eficientes que method1. Yo prefiero el método 2 . Para el ejemplo mencionado anteriormente, time (method1): time (method2): time (method3) = 1: 1: 1.7

para bucle será iterado a través del índice ...

considera que tienes una lista,

[5, 7, 13, 29, 65, 91]

tiene usando la variable de lista llamada lis . y tú usas el mismo para eliminar ...

tu variable

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

durante la 5ta iteración,

su número 35 no era un número primo, por lo que lo eliminó de una lista.

lis.remove(y)

y luego siguiente valor (65) pasa al índice anterior.

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

el puntero de la cuarta iteración se movió a la quinta ..

Es por eso que su bucle no cubre 65 desde que se movió al índice anterior.

por lo que no debe hacer referencia a la lista en otra variable que aún sea original en lugar de copiar.

ite = lis #dont do it will reference instead copy

haga lo mismo con la copia de la lista usando list[::?

ahora te lo daremos,

[5, 7, 13, 29]

El problema es que eliminó un valor de una lista durante la iteración, luego el índice de su lista colapsará.

para que puedas probar la comprensión en su lugar.

que admite todos los iterables como, lista, tupla, dict, cadena, etc.

Para cualquier cosa que tenga el potencial de ser realmente grande, uso lo siguiente.

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

Eso debería ser significativamente más rápido que cualquier otra cosa.

En algunas situaciones, donde estás haciendo más que simplemente filtrar una lista un elemento a la vez, quieres que tu iteración cambie mientras se itera.

Aquí hay un ejemplo en el que copiar la lista de antemano es incorrecto, la iteración inversa es imposible y una comprensión de la lista tampoco es una opción.

""" Sieve of Eratosthenes """

def generate_primes(n):
    """ Generates all primes less than n. """
    primes = list(range(2,n))
    idx = 0
    while idx < len(primes):
        p = primes[idx]
        for multiple in range(p+p, n, p):
            try:
                primes.remove(multiple)
            except ValueError:
                pass #EAFP
        idx += 1
        yield p

Si va a utilizar la nueva lista más adelante, simplemente puede establecer el elemento en Ninguno y, a continuación, juzgarlo en el bucle posterior, como este

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

De esta manera, no necesita copiar la lista y es más fácil de entender.

Proponga una lista de números y desea eliminar todos los no divisibles entre 3,

list_number =[i for i in range(100)]

utilizando list comprensión , esto creará una nueva lista y creará un nuevo espacio de memoria

new_list =[i for i in list_number if i%3!=0]

utilizando la función lambda filter , esto creará una nueva lista resultante y consumirá espacio de memoria

new_list = list(filter(lambda x:x%3!=0, list_number))

sin consumir espacio de memoria para la nueva lista y modificar la lista existente

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)

De inmediato, desea crear una copia de la lista para tenerla como referencia cuando esté iterando y eliminando tuplas en esa lista que cumplan con ciertos criterios.

Luego, depende del tipo de lista que desee para el resultado, ya sea una lista de las tuplas eliminadas o una lista de las tuplas que no se eliminan.

Como señaló David, recomiendo la comprensión de la lista para mantener los elementos que no desea eliminar.

somelist = [x for x in somelist if not determine(x)]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top