Para muchos casos de uso, la respuesta que desea es:
ys = set(y)
[item for item in x if item not in ys]
Este es un híbrido entre la respuesta de aaronasterling y la respuesta de quantumSoup .
La versión de aaronasterling hace len(y)
comparaciones de elementos para cada elemento x
, por lo que lleva tiempo cuadrático. La versión de quantumSoup usa conjuntos, por lo que realiza una sola búsqueda de conjuntos de tiempo constante para cada elemento en x
, pero porque convierte ambos x
yy
en conjuntos, pierde el orden de sus elementos.
Al convertir solo y
en un conjunto e iterar x
en orden, obtienes lo mejor de ambos mundos: tiempo lineal y preservación del orden. *
Sin embargo, esto todavía tiene un problema con la versión de quantumSoup: requiere que sus elementos sean hashable. Eso está más o menos integrado en la naturaleza de los conjuntos. ** Si está tratando de restar, por ejemplo, una lista de dictos de otra lista de dictos, pero la lista para restar es grande, ¿qué debe hacer?
Si puede decorar sus valores de alguna manera para que se puedan compartir, eso resuelve el problema. Por ejemplo, con un diccionario plano cuyos valores son en sí mismos hashables:
ys = {tuple(item.items()) for item in y}
[item for item in x if tuple(item.items()) not in ys]
Si sus tipos son un poco más complicados (por ejemplo, a menudo se trata de valores compatibles con JSON, que son hashable, o listas o dictados cuyos valores son recursivamente del mismo tipo), aún puede usar esta solución. Pero algunos tipos simplemente no se pueden convertir en algo hashaable.
Si sus elementos no son, y no se pueden hacer, hashables, pero son comparables, al menos puede obtener un tiempo de registro lineal ( O(N*log M)
que es mucho mejor que el O(N*M)
tiempo de la solución de la lista, pero no tan bueno como el O(N+M)
tiempo de la solución establecida) ordenando y usando bisect
:
ys = sorted(y)
def bisect_contains(seq, item):
index = bisect.bisect(seq, item)
return index < len(seq) and seq[index] == item
[item for item in x if bisect_contains(ys, item)]
Si sus artículos no son hashables ni comparables, entonces está atrapado con la solución cuadrática.
* Tenga en cuenta que también puede hacerlo utilizando un par de OrderedSet
objetos, para los cuales puede encontrar recetas y módulos de terceros. Pero creo que esto es más simple.
** La razón por la que las búsquedas de conjuntos son de tiempo constante es que todo lo que tiene que hacer es calcular el valor hash y ver si hay una entrada para ese hash. Si no puede cambiar el valor, esto no funcionará.