Für viele Anwendungsfälle lautet die gewünschte Antwort:
ys = set(y)
[item for item in x if item not in ys]
Dies ist ein Hybrid zwischen aaronasterling Antwort und quantumSoup Antwort .
Die Version von aaronasterling führt Elementvergleiche len(y)
für jedes Element in durch x
, daher dauert es quadratisch. In der Version von quantumSoup werden Mengen verwendet, sodass für jedes Element in eine einzelne Mengen-Suche mit konstanter Zeit durchgeführt x
wird. Da jedoch beide x
und y
in Mengen konvertiert werden, verliert sie die Reihenfolge Ihrer Elemente.
Wenn Sie nur y
in eine Menge konvertieren und in der richtigen x
Reihenfolge iterieren , erhalten Sie das Beste aus beiden Welten - lineare Zeit und Ordnungserhaltung. *
Dies hat jedoch immer noch ein Problem mit der Version von quantumSoup: Es erfordert, dass Ihre Elemente hashbar sind. Das ist so ziemlich in die Natur von Mengen eingebaut. ** Wenn Sie beispielsweise versuchen, eine Liste von Diktaten von einer anderen Liste von Diktaten zu subtrahieren, die zu subtrahierende Liste jedoch groß ist, was tun Sie dann?
Wenn Sie Ihre Werte so dekorieren können, dass sie hashbar sind, löst dies das Problem. Zum Beispiel mit einem flachen Wörterbuch, dessen Werte selbst hashbar sind:
ys = {tuple(item.items()) for item in y}
[item for item in x if tuple(item.items()) not in ys]
Wenn Ihre Typen etwas komplizierter sind (z. B. häufig mit JSON-kompatiblen Werten, die hashbar sind, oder Listen oder Diktaten, deren Werte rekursiv vom gleichen Typ sind), können Sie diese Lösung weiterhin verwenden. Einige Typen können jedoch nicht in etwas Hashbares konvertiert werden.
Wenn Ihre Elemente nicht hashbar sind und nicht erstellt werden können, aber vergleichbar sind, können Sie zumindest eine logarithmisch lineare Zeit erhalten ( O(N*log M)
die viel besser ist als die O(N*M)
Zeit der Listenlösung , aber nicht so gut wie) die O(N+M)
Zeit der eingestellten Lösung) durch Sortieren und Verwenden von 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)]
Wenn Ihre Artikel weder hashbar noch vergleichbar sind, bleiben Sie bei der quadratischen Lösung.
* Beachten Sie, dass Sie dies auch tun können, indem Sie ein Objektpaar verwenden OrderedSet
, für das Sie Rezepte und Module von Drittanbietern finden. Aber ich denke das ist einfacher.
** Der Grund, warum Set-Lookups eine konstante Zeit sind, ist, dass sie nur den Wert hashen und prüfen müssen, ob es einen Eintrag für diesen Hash gibt. Wenn der Wert nicht gehasht werden kann, funktioniert dies nicht.