Ich möchte etwas Ähnliches tun:
>>> x = [1,2,3,4,5,6,7,8,9,0]
>>> x
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> y = [1,3,5,7,9]
>>> y
[1, 3, 5, 7, 9]
>>> y - x # (should return [2,4,6,8,0])
Dies wird jedoch von Python-Listen nicht unterstützt. Wie geht das am besten?
Antworten:
Verwenden Sie ein Listenverständnis:
Wenn Sie die
-
Infix-Syntax verwenden möchten , können Sie einfach Folgendes tun:Sie können es dann wie folgt verwenden:
Wenn Sie jedoch keine Listeneigenschaften benötigen (z. B. Reihenfolge), verwenden Sie einfach Sets, wie in den anderen Antworten empfohlen.
quelle
list
für Variablennamen verwenden, da dies denlist
Konstruktor beschattet . Wenn Sie "Liste" verwenden, stellen Sie bitte einen Unterstrich voran. Außerdem haben Sie durch das*
[1,1,2,2] - [1,2]
Sie eine leere Liste.[1,1,2,2] - [2]
gibt[1,1]
es also nicht wirklich Listensubtraktion, es ist eher wie "Liste aus Liste X ohne Elemente aus Menge Y " .y
in einen konvertiert wird (was den Kosten der Originalarbeit ähnlich ist). Sie müssten entweder außerhalb des Listcomp, dann testen oder als ungeheuerlicher Hack, der verschachtelte Listcomps missbraucht, um den als Einzeiler zwischenzuspeichern . Eine etwas weniger hässliche Einzeilerlösung, die eine angemessene Leistung erbringt, wäre die Verwendung, da das Argument to nur einmal konstruiert wird.set
yset = set(y)
if item not in yset
[item for yset in [set(y)] for item in x if item not in yset]
yset
list(itertools.filterfalse(set(y).__contains__, x))
filterfalse
Verwenden Sie die eingestellte Differenz
Oder Sie müssen nur x und y setzen, damit Sie keine Konvertierungen vornehmen müssen.
quelle
TypeError: unhashable type: 'dict'
Das ist eine "Set-Subtraktions" -Operation. Verwenden Sie dazu die eingestellte Datenstruktur.
In Python 2.7:
Ausgabe:
quelle
Wenn doppelte und bestellte Artikel ein Problem sind:
[i for i in a if not i in b or b.remove(i)]
quelle
O(m * n)
Laufzeit ist (und ich erschrecke, wenn ein Listcomp Nebenwirkungen enthält); Sie können es verbessern, indemcollections.Counter
Sie dieO(m + n)
Laufzeit abrufen.Für viele Anwendungsfälle lautet die gewünschte Antwort:
Dies ist ein Hybrid zwischen aaronasterling Antwort und quantumSoup Antwort .
Die Version von aaronasterling führt Elementvergleiche
len(y)
für jedes Element in durchx
, 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ührtx
wird. Da jedoch beidex
undy
in Mengen konvertiert werden, verliert sie die Reihenfolge Ihrer Elemente.Wenn Sie nur
y
in eine Menge konvertieren und in der richtigenx
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:
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 dieO(N*M)
Zeit der Listenlösung , aber nicht so gut wie) dieO(N+M)
Zeit der eingestellten Lösung) durch Sortieren und Verwenden vonbisect
: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.
quelle
Das Nachschlagen von Werten in Sätzen ist schneller als das Nachschlagen in Listen:
Ich glaube, das wird etwas besser skalieren als:
Beide behalten die Reihenfolge der Listen bei.
quelle
set(y)
und nichty
in einen neuen Satz konvertiert ? Andernfalls benötigen Sie die Antwort von abarnert :ys = set(y); [i for i in x if i not in ys]
.if i not in set(y)
25% länger dauert alsif i not in y
(woy
ist eine Liste). Das Vorkonvertieren des Sets dauert 55% weniger Zeit. Getestet mit ziemlich kurzenx
undy
, aber Unterschiede sollten mit der Länge stärker werden, wenn überhaupt.y
für jedes Element von iterieren und hashen mussx
; Wenn der Gleichheitsvergleich im Vergleich zur Hash-Berechnung nicht wirklich teuer ist, verliert dies immer an Klarheititem not in y
.Wenn die Listen doppelte Elemente zulassen, können Sie Zähler aus Sammlungen verwenden:
Wenn Sie die Reihenfolge der Elemente von x beibehalten müssen:
quelle
Counter.subtract
entfernt keine nullwertigen Elemente (-
und-=
tut dies, aber nichtsubtract
), sodass Sie niemals aufhören würden, Elemente zu entfernen. Sie würden ersetzen möchtennot v in c
mitnot c[v]
(die Renditen für nicht vorhandene Elemente Null, so dass Sie sicher die Rückkehr für „zeroiness“ über testennot
).Die anderen Lösungen haben eines der wenigen Probleme:
x = [1, 2, 2, 2]
undy = [2, 2]
konvertiereny
in aset
, und entfernen entweder alle übereinstimmenden Elemente ([1]
nur verlassen) oder entfernen jedes einzelne eindeutige Element (verlassen[1, 2, 2]
), wenn das richtige Verhalten darin besteht,2
zweimal zu entfernen . verlassen[1, 2]
, oderO(m * n)
arbeiten dort, wo eine optimale LösungO(m + n)
funktionieren kannAlain war auf dem richtigen Weg
Counter
, um # 2 und # 3 zu lösen, aber diese Lösung wird die Bestellung verlieren. Die Lösung, die die Reihenfolge beibehält (Entfernen der erstenn
Kopien jedes Werts fürn
Wiederholungen in denlist
zu entfernenden Werten), lautet:Probieren Sie es online aus!
Um die letzten Kopien jedes Elements zu entfernen , ändern Sie einfach die
for
Schleife infor val in reversed(x):
und fügen Sie sieout.reverse()
unmittelbar nach dem Verlassen derfor
Schleife hinzu.Die Konstruktion der
Counter
sichO(n)
in Bezug auf diey
‚s Länge, Iterierenx
istO(n)
in Bezug auf diex
‘ s Länge undCounter
Mitgliedschaft Tests und Mutation sindO(1)
, währendlist.append
abgeschriebenO(1)
(a gegebenappend
sein kannO(n)
, aber für vieleappend
s, die Gesamt Big-O mittelt ,O(1)
da immer weniger von ihnen erfordern eine Neuzuweisung), so dass die Gesamtarbeit erledigt istO(m + n)
.Sie können auch testen, ob Elemente darin enthalten sind
y
, die nichtx
durch Testen entfernt wurden:quelle
int
s in ein Array mit fester Länge zählen) oder muss mehr als nurO(m + n)
arbeiten (z. B. die nächstbeste große -O wäre, eine Sortierunglist
von eindeutigen Wert / Anzahl-Paaren zuO(1)
dict
erstellen undO(log n)
Suchvorgänge in binäre Suchvorgänge umzuwandeln . Sie benötigen eindeutige Werte mit ihrer Anzahl , nicht nur sortierte nicht eindeutige Werte, da Sie sonstO(n)
Kosten für das Entfernen der Werte zahlen würden Elemente aus dem sortiertenlist
).Versuche dies.
quelle
Ich denke, der einfachste Weg, dies zu erreichen, ist die Verwendung von set ().
quelle
Die Antwort , die von gut aussieht @aaronasterling, ist es jedoch nicht mit der Standardoberfläche von Liste kompatibel:
x = MyList(1, 2, 3, 4)
vsx = MyList([1, 2, 3, 4])
. Daher kann der folgende Code als Python-Listen-freundlicher verwendet werden:Beispiel:
quelle
Ich denke das geht schneller:
quelle
In diesem Beispiel werden zwei Listen abgezogen:
quelle