Pour de nombreux cas d'utilisation, la réponse que vous souhaitez est:
ys = set(y)
[item for item in x if item not in ys]
Il s'agit d'un hybride entre la réponse d' Aaronasterling et la réponse de QuantumSoup .
La version de aaronasterling fait des len(y)
comparaisons d'éléments pour chaque élément dans x
, donc cela prend du temps quadratique. La version de quantumSoup utilise des ensembles, elle effectue donc une seule recherche d'ensemble à temps constant pour chaque élément dans x
- mais, comme elle convertit les deux x
et y
en ensembles, elle perd l'ordre de vos éléments.
En convertissant uniquement y
en un ensemble et en itérant x
dans l'ordre, vous obtenez le meilleur des deux mondes: le temps linéaire et la préservation de l'ordre. *
Cependant, cela a toujours un problème avec la version de quantumSoup: cela nécessite que vos éléments soient lavables. C'est à peu près intégré dans la nature des ensembles. ** Si vous essayez, par exemple, de soustraire une liste de dict d'une autre liste de dict, mais que la liste à soustraire est grande, que faites-vous?
Si vous pouvez décorer vos valeurs de manière à ce qu'elles soient lavables, cela résout le problème. Par exemple, avec un dictionnaire plat dont les valeurs sont elles-mêmes hachables:
ys = {tuple(item.items()) for item in y}
[item for item in x if tuple(item.items()) not in ys]
Si vos types sont un peu plus compliqués (par exemple, vous avez souvent affaire à des valeurs compatibles JSON, qui sont hachables, ou à des listes ou des codes dont les valeurs sont récursivement du même type), vous pouvez toujours utiliser cette solution. Mais certains types ne peuvent tout simplement pas être convertis en quelque chose de lavable.
Si vos articles ne sont pas, et ne peuvent pas être, lavables, mais ils sont comparables, vous pouvez au moins obtenir un temps log-linéaire ( O(N*log M)
, ce qui est beaucoup mieux que le O(N*M)
temps de la solution de liste, mais pas aussi bon que le O(N+M)
temps de la solution réglée) en triant et en utilisant 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 vos articles ne sont ni lavables ni comparables, alors vous êtes coincé avec la solution quadratique.
* Notez que vous pouvez également le faire en utilisant une paire d' OrderedSet
objets, pour laquelle vous pouvez trouver des recettes et des modules tiers. Mais je pense que c'est plus simple.
** La raison pour laquelle les recherches définies sont à temps constant est qu'il suffit de hacher la valeur et de voir s'il existe une entrée pour ce hachage. S'il ne peut pas hacher la valeur, cela ne fonctionnera pas.