2010-03-25 9 views

Respuesta

86
>>> a = range(1, 10) 
>>> [x for x in a if x not in [2, 3, 7]] 
[1, 4, 5, 6, 8, 9] 
+7

¿Qué pasa si tengo una lista '[1,2,2,2,3,4]' y una sublista '[2,3]', entonces el resultado debería ser '[1,2,2,4 ] ', ¿hay alguna manera Pythonic de hacer eso? – user

+0

@user esto te lleva la mayor parte del camino, pero tu problema es diferente. l = [1,2,2,3,4] sl = [2,3] [x para x en [l [n: n + 2] para n en rango (0, len (l)) [ :: 2]] si x! = Sl] – jsh

11
a = range(1,10) 
itemsToRemove = set([2, 3, 7]) 
b = filter(lambda x: x not in itemsToRemove, a) 

o

b = [x for x in a if x not in itemsToRemove] 

No cree el conjunto dentro de la lambda o dentro de la comprensión. Si lo haces, será recreado en cada iteración, derrotando el punto de usar un conjunto.

+1

Excepto que crea N conjuntos, siendo N len (a). – FogleBird

+0

Crea un solo conjunto en la creación de la función lambda –

+0

Buen punto, FogleBird. Necesita crearlo fuera de lambda o enumerar la comprensión. – Yaroslav

5

Otros han sugerido formas de hacer una nueva lista después de filtrar, p.

newl = [x for x in l if x not in [2,3,7]] 

o

newl = filter(lambda x: x not in [2,3,7], l) 

pero a partir de su pregunta que parece que quiere en lugar de modificación para que pueda hacer esto, esto también será mucho más rápido si la lista original es largo y artículos que ser eliminado menos

l = range(1,10) 
for o in set([2,3,7,11]): 
    try: 
     l.remove(o) 
    except ValueError: 
     pass 

print l 

salida: [1, 4, 5, 6, 8, 9]

estoy comprobando para ValueError excepción por lo que funciona incluso si los artículos no están en la lista original.

Además, si no necesita solución de modificación in situ por S.Mark es más simple.

+0

si realmente necesita una modificación in situ, las respuestas anteriores se pueden modificar a: 'a [:] = [x para x en a si x no en [2,3,7]]'. Esto será más rápido que tu código. –

+2

sí a [:] se puede usar, pero no es obvio que sea más rápido, para listas largas con pocos valores para eliminar mi código será mucho más rápido, p. try list para eliminar = [1] :) –

+0

@Anurag: Parece que tienes razón; las pruebas de tiempo hacen que parezca que quitarlas en su lugar es más rápido. –

5

La forma más sencilla es

>>> a = range(1, 10) 
>>> for x in [2, 3, 7]: 
... a.remove(x) 
... 
>>> a 
[1, 4, 5, 6, 8, 9] 

Un posible problema aquí es que cada vez que se llama a eliminar(), todos los artículos son barajadas por la lista para llenar el agujero. Entonces, si a crece muy grande, esto terminará siendo bastante lento.

De esta manera se crea una nueva lista. La ventaja es que se evita todo el mezclarse del primer enfoque

>>> removeset = set([2, 3, 7]) 
>>> a = [x for x in a if x not in removeset] 

Si desea modificar a en su lugar, sólo se requiere un pequeño cambio

>>> removeset = set([2, 3, 7]) 
>>> a[:] = [x for x in a if x not in removeset] 
+0

@gnibbler, su afirmación * "Así que si' a' crece muy grande, esto terminará siendo bastante lento. "* Es un poco engañoso. Si solo la longitud de 'a' no está limitada, todos los fragmentos que proporcionó son O (n). El problema ** real ** con 'eliminar' es que solo elimina * la primera aparición * de sus argumentos, no todas las ocurrencias. También es más acorde con escribir un código claro e idiomático para hacer una nueva lista en lugar de mutar la anterior. –

+0

@Mike, intenté mantener la respuesta simple ya que el OP ha usado la etiqueta de principiante. –

+3

"simple" no es excusa para * incorrecto *. –

4
>>> a=range(1,10) 
>>> for i in [2,3,7]: a.remove(i) 
... 
>>> a 
[1, 4, 5, 6, 8, 9] 

>>> a=range(1,10) 
>>> b=map(a.remove,[2,3,7]) 
>>> a 
[1, 4, 5, 6, 8, 9] 
+0

No use 'map' para los efectos secundarios. 'map' es para recoger el resultado de un grupo de llamadas. Para los bucles son la herramienta para hacer algo un montón de veces. –

+0

si lo que quiere decir con efectos secundarios son esos "ninguno" devueltos por 'mapa', entonces puede" enmascararse ". Aparte de eso, sigue siendo válido, y me gusta la concisión de la misma. – ghostdog74

29

Si no lo hace tiene valores repetidos, puede usar establecer la diferencia.

x = set(range(10)) 
y = x - set([2, 3, 7]) 
# y = set([0, 1, 4, 5, 6, 8, 9]) 

y luego volver a la lista, si es necesario.

+0

Tenga en cuenta que esto mezclará la lista resultante. –

+1

El orden de la lista puede cambiar, pero de forma determinista. No está "barajado" en el sentido aleatorio. – dansalmo

+3

también, si su lista original x tiene duplicados, después de la operación set(), solo se guarda uno. –

14

Estaba buscando una forma rápida de hacer el tema, así que hice algunos experimentos con las formas sugeridas. Y me sorprendieron los resultados, así que quiero compartirlo contigo.

Los experimentos se realizaron utilizando pythonbenchmark herramienta y con

a = range(1,50000) # Source list 
b = range(1,15000) # Items to remove 

Resultados:

def comprehension(a, b): 
    return [x for x in a if x not in b] 

5 intentos, tiempo medio de 12,8 seg

def filter_function(a, b): 
    return filter(lambda x: x not in b, a) 

5 intentos, tiempo medio de 12,6 seg

def modification(a,b): 
    for x in b: 
     try: 
      a.remove(x) 
     except ValueError: 
      pass 
    return a 

5 intentos, el tiempo promedio 0,27 seg

def set_approach(a,b): 
    return list(set(a)-set(b)) 

5 intentos, tiempo medio 0,0057 sec

También hice otra medición con el tamaño de las entradas más grandes para las dos últimas funciones

a = range(1,500000) 
b = range(1,100000) 

Y los resultados:

Para la modificación (quitar método) - tiempo promedio es de 252 segundos para la aproximación conjunto - tiempo promedio es de 0,75 segundo

Así se puede ver que el enfoque con conjuntos es significativamente más rápido que otros. Sí, no mantiene artículos similares, pero si no lo necesita, es para usted. Y casi no hay diferencia entre la comprensión de la lista y el uso de la función de filtro. Usar 'eliminar' es ~ 50 veces más rápido, pero modifica la lista de fuentes. Y la mejor opción es usar conjuntos: ¡es más de 1000 veces más rápido que la comprensión de listas!

+0

muy interesante. No hubiera usado set, intuitivamente la conversión debería agregar sobrecarga. aparentemente mi intuición estaba equivocada. gracias por la idea – lhk

Cuestiones relacionadas