Hier sind einige Versuche:
%Vor% Nachdem ich nun einen Moment zum Nachdenken hatte, merke ich, dass das L2 + L3
Ding eine temporäre Liste erstellt, die sofort weggeworfen wird. Also ein noch besserer Weg ist:
Update: Ich sehe extravagante Behauptungen über die Leistung, und ich möchte behaupten, dass meine Lösung so schnell wie möglich war. Das Erstellen von Zwischenergebnissen, egal ob es sich um Zwischenlisten oder Zwischeniteratoren handelt, die dann wiederholt aufgerufen werden müssen, wird immer langsamer sein, als einfach L2
und L3
für den Satz direkt zu durchlaufen, wie ich es hier getan habe.
Alle anderen Alternativen (die ich mir vorstellen kann) werden langsamer sein. Wenn wir zum Beispiel die Schleifen selbst machen, anstatt den set()
-Konstruktor machen zu lassen, entstehen zusätzliche Kosten:
Wenn Sie Iteratoren verwenden, werden alle diese Funktionen und Rückrufe, die sie beinhalten, natürlich noch teurer:
%Vor% Ich glaube also, dass die Antwort, die ich letzte Nacht gegeben habe, immer noch weit entfernt ist (für Werte von "weit und weg" größer als etwa 5μs, offensichtlich) die besten, es sei denn, der Fragesteller wird Duplikate in L1
haben und will sie haben wird jedes Mal für jedes Mal entfernt, wenn das Duplikat in einer der anderen Listen erscheint.
update ::: post enthält einen Verweis auf falsche Behauptungen von schlechter Leistung von Sätzen im Vergleich zu frozensets. Ich behaupte, dass es immer noch sinnvoll ist, in dieser Instanz ein eingefrorenes Set zu verwenden, obwohl es nicht nötig ist, das Set selbst zu hacken, nur weil es semantisch korrekter ist. Obwohl ich in der Praxis nicht die zusätzlichen 6 Zeichen eingeben würde. Ich fühle mich nicht motiviert, den Post zu bearbeiten und zu bearbeiten, also sei nur darauf hingewiesen, dass die "Anschuldigungen" Links zu einigen falsch ausgeführten Tests verlinken. Die blutigen Details sind in den Kommentaren zusammengefasst. ::: update
Das zweite Stück Code geschrieben von Brandon Craig Rhodes ist ganz gut, aber da er nicht auf meinen Vorschlag reagiert hat, ein eingefrorenes Set zu verwenden (na ja, nicht, als ich anfing, dies zu schreiben), werde ich weitermachen und es selbst posten.
Die gesamte zugrunde liegende Aufgabe besteht darin, zu überprüfen, ob jeder einer Reihe von Werten ( L1
) in einer anderen Menge von Werten enthalten ist; Diese Menge von Werten ist der Inhalt von L2
und L3
. Die Verwendung des Wortes "set" in diesem Satz ist bezeichnend: Obwohl L2
und L3
list
s sind, interessieren wir uns nicht für ihre listenähnlichen Eigenschaften, wie die Reihenfolge, in der sich ihre Werte befinden oder wie viele von ihnen enthalten sie jeweils. Wir kümmern uns nur um das Set (dort ist es wieder) von Werten, die sie zusammen enthalten.
Wenn diese Menge von Werten als eine Liste gespeichert wird, müssen Sie nacheinander die Listenelemente durchgehen und jedes einzelne prüfen. Es ist relativ zeitaufwendig und es ist eine schlechte Semantik: Es ist wieder eine "Menge" von Werten, keine Liste. Also hat Python diese ordentlichen Settypen, die eine Reihe einzigartiger Werte enthalten, und kann Ihnen schnell sagen, ob ein Wert darin enthalten ist oder nicht. Das funktioniert ähnlich wie die dict
-Typen von python, wenn Sie nach einem Schlüssel suchen.
Der Unterschied zwischen sets und frozensets besteht darin, dass Sets veränderbar sind, was bedeutet, dass sie nach der Erstellung geändert werden können. Dokumentation zu beiden Typen ist hier .
Da die Menge, die wir erstellen müssen, die Vereinigung der Werte, die in L2
und L3
gespeichert sind, nicht geändert wird, sobald sie erstellt wurde, ist es semantisch angemessen, einen unveränderlichen Datentyp zu verwenden. Dies hat auch angeblich Leistungsvorteile. Nun, es macht Sinn, dass es einen Vorteil hätte; Andernfalls hätte Python frozenset
als eingebaut?
update ...
Brandon hat diese Frage beantwortet: Der wahre Vorteil von eingefrorenen Sets ist, dass ihre Unveränderlichkeit es ihnen ermöglicht, zu sein hashbar , damit sie Wörterbuchschlüssel oder Mitglieder anderer Sets sein können.
Ich habe einige informelle Timing-Tests durchgeführt, bei denen die Geschwindigkeit für die Erstellung und Suche nach relativ großen (3000 Elemente) eingefrorenen und veränderbaren Mengen verglichen wurde; Es gab keinen großen Unterschied. Dies steht im Widerspruch zu der obigen Verbindung, unterstützt aber, was Brandon über ihre Identität sagt, aber für den Aspekt der Veränderlichkeit.
... update
Nun, da frozensets unveränderbar sind, haben sie keine Update-Methode. Brandon verwendete die set.update
-Methode, um zu vermeiden, dass eine temporäre Liste auf dem Weg zur Erstellung erstellt und dann verworfen wird. Ich werde einen anderen Ansatz wählen.
Dieser Generatorausdruck macht items
zu einem Iterator, über den Inhalt von L2
und L3
. Nicht nur das, aber es macht es, ohne eine ganze Liste voller Zwischenobjekte zu erstellen. Die Verwendung von geschachtelten for
-Ausdrücken in Generatoren ist ein wenig verwirrend, aber ich sorge dafür, dass es sortiert bleibt, indem ich mich daran erinnere, dass sie in der gleichen Reihenfolge verschachtelt werden wie beim Schreiben von aktuellen Schleifen, z. B.
Diese Generatorfunktion entspricht dem Generatorausdruck, den wir items
zugewiesen haben. Nun, außer dass es eine parametrisierte Funktionsdefinition anstelle einer direkten Zuweisung zu einer Variablen ist.
Wie auch immer, genug Exkurs. Die große Sache mit Generatoren ist, dass sie eigentlich gar nichts machen. Nun, zumindest nicht sofort: Sie richten nur Arbeit ein, die später ausgeführt werden soll, wenn der Generatorausdruck iteriert ist. Dies wird formal als faul bezeichnet. Wir werden das tun (nun, ich bin es sowieso), indem ich items
an die Funktion frozenset
übergebe, die darüber iteriert und ein frostiges, kaltes, gefrorenes Set zurückgibt.
Sie könnten die letzten beiden Zeilen kombinieren, indem Sie den Generatorausdruck direkt in den Aufruf von frozenset
:
Dieser nette syntaktische Trick funktioniert, solange der Iterator , der vom Generator-Ausdruck erzeugt wird, der einzige Parameter ist zu der Funktion, die Sie anrufen. Andernfalls müssen Sie es in seiner üblichen separaten Klammer schreiben, so wie Sie ein Tupel als Argument für die Funktion übergeben haben.
Nun können wir eine neue Liste auf die gleiche Weise wie Brandon erstellen, mit einem Listenverständnis . Diese verwenden die gleiche Syntax wie Generator-Ausdrücke und machen im Prinzip dasselbe, außer dass sie eifrig statt faul sind (dies sind wiederum technische Begriffe), also sie Machen Sie sich bereit, über die Elemente zu iterieren und daraus eine Liste zu erstellen.
%Vor% Dies entspricht der Übergabe eines Generatorausdrucks an list
, z. B.
aber mehr idiomatisch.
Damit wird die Liste L4
erstellt, die die Elemente von L1
enthält, die weder in L2
noch in L3
waren, wobei die Reihenfolge, in der sie sich ursprünglich befanden, und die Anzahl derer, die es gab, beibehalten wurde .
Wenn Sie nur wissen wollen, welche Werte in L1
sind, aber nicht in L2
oder L3
, ist es viel einfacher: Sie erstellen nur diesen Satz:
Sie können eine Liste daraus erstellen genauso wie st0le , aber das ist vielleicht nicht das was du willst. Wenn Sie wirklich die Menge von Werten wollen, die nur in L1
gefunden werden, haben Sie möglicherweise einen guten Grund, diese Menge als set
oder zu behalten in der Tat ein frozenset
:
... Annnnd , jetzt für etwas ganz anderes:
%Vor%Dies ist vielleicht weniger pythonesque als die Liste-Verständnis-Antwort, hat aber ein einfacheres Aussehen:
%Vor%Der Vorteil hier ist, dass wir die Reihenfolge der Liste beibehalten, und wenn doppelte Elemente vorhanden sind, entfernen wir nur eins für jedes Mal, wenn es in l2 erscheint.
Wenn Sie solche Vorgänge in Listen ausführen, kann dies die Leistung Ihres Programms sehr bald beeinträchtigen. Was passiert, ist mit jedem entfernen, List Operationen machen einen frischen malloc & amp; Elemente verschieben. Dies kann teuer sein, wenn Sie eine sehr große Liste haben oder nicht. Also würde ich das vorschlagen -
Ich gehe davon aus, dass Ihre Liste einzigartige Elemente enthält. Andernfalls müssen Sie in Ihrem Diktat eine Liste mit doppelten Werten pflegen. Wie auch immer für die Daten, die du zur Verfügung gestellt hast, hier ist es -
METHODE 1
%Vor% METHODE 2
Wenn das alles zu viel Code aussieht. Dann könnten Sie set
verwenden. Aber auf diese Weise verliert Ihre Liste alle doppelten Elemente.
Ich denke, die Antwort von intuited ist zu lang für solch ein einfaches Problem, und Python hat bereits eine eingebaute Funktion, um zwei Listen als Generator zu verketten.
Die Vorgehensweise ist wie folgt:
itertools.chain
, um L2 und L3 zu verketten, ohne eine speicherintensive Kopie zu erstellen x in someset
) O (1) ist, wird dies sehr schnell sein. Und jetzt der Code:
%Vor%Dies sollte eine der schnellsten, einfachsten und am wenigsten speicherintensiven Lösung sein.
Tags und Links python list-comprehension