Angenommen, Folgendes:
>>> s = set([1, 2, 3])
Wie bekomme ich einen Wert (irgendeinen Wert) heraus, s
ohne es zu tun s.pop()
? Ich möchte das Element im Set belassen, bis ich sicher bin, dass ich es entfernen kann - etwas, dessen ich mir erst nach einem asynchronen Aufruf eines anderen Hosts sicher sein kann.
Schnell und dreckig:
>>> elem = s.pop()
>>> s.add(elem)
Aber kennen Sie einen besseren Weg? Idealerweise in konstanter Zeit.
union
usw. ausführen, ohne Elemente daraus zu entnehmen . Zum Beispiel wirdnext(iter({3,2,1}))
immer zurückgegeben1
, wenn Sie dachten, dass dies ein zufälliges Element zurückgeben würde - würde dies nicht der Fall sein. Vielleicht verwenden Sie nur die falsche Datenstruktur? Was ist der Anwendungsfall?Antworten:
Zwei Optionen, bei denen nicht das gesamte Set kopiert werden muss:
Oder...
Im Allgemeinen unterstützen Sets jedoch keine Indizierung oder Aufteilung.
quelle
iter(s).next()
ist nicht brutto, aber großartig. Ganz allgemein, um ein beliebiges Element von einem iterierbaren Objekt zu übernehmen. Ihre Wahl, wenn Sie vorsichtig sein möchten, wenn die Sammlung leer ist.next(iter(your_list or []), None)
Keine Sätze und leere Sätze zu handhabenDer kleinste Code wäre:
Offensichtlich würde dies eine neue Liste erstellen, die jedes Mitglied des Satzes enthält, also nicht großartig, wenn Ihr Satz sehr groß ist.
quelle
next(iter(s))
nur überschreitetlist(s)[0]
durch drei Zeichen und ist ansonsten dramatisch überlegen in Zeit und Raum Komplexität. Während die Behauptung des "kleinsten Codes" trivial wahr ist, ist es auch trivial wahr, dass dies der schlechteste mögliche Ansatz ist. Selbst das manuelle Entfernen und anschließende Hinzufügen des entfernten Elements zum ursprünglichen Satz ist besser als "einen ganz neuen Container zu erstellen, nur um das erste Element zu extrahieren", was offensichtlich verrückt ist. Was mich mehr beschäftigt ist, dass 38 Stackoverflowers dies tatsächlich positiv bewertet haben. Ich weiß nur, dass ich das im Produktionscode sehen werde.min(s)
werden noch weniger Zeichen verwendet, während Sie genauso schrecklich und ineffizient sind.min(s)
ist etwas schneller alsnext(iter(s))
für Sätze der Größe 1, und ich bin zu dieser Antwort gekommen, um speziell das Sonderelement aus Sätzen zu extrahieren von Größe 1.Ich habe mich gefragt, wie die Funktionen für verschiedene Sets funktionieren, also habe ich einen Benchmark durchgeführt:
Dieses Diagramm zeigt deutlich, dass einige Ansätze (
RandomSample
,SetUnpacking
undListIndex
) von der Größe des Satzes abhängen und im allgemeinen Fall vermieden werden sollten (zumindest wenn die Leistung wichtig sein könnte ). Wie bereits in den anderen Antworten gezeigt, ist der schnellste WegForLoop
.Solange jedoch einer der Ansätze mit konstanter Zeit verwendet wird, ist der Leistungsunterschied vernachlässigbar.
iteration_utilities
(Disclaimer: Ich bin der Autor) eine Komfortfunktion für diesen Anwendungsfall:first
:Ich habe es auch in den obigen Benchmark aufgenommen. Es kann mit den anderen beiden "schnellen" Lösungen konkurrieren, aber der Unterschied ist in keiner Weise groß.
quelle
tl; dr
for first_item in muh_set: break
bleibt der optimale Ansatz in Python 3.x. Verfluche dich, Guido.Du machst das
Willkommen zu einem weiteren Satz von Python 3.x-Timings, extrapoliert aus wr. 's ausgezeichnete Python 2.x-spezifische Antwort . Im Gegensatz zu AChampions ebenso hilfreicher Python 3.x-spezifischer Antwort werden in den folgenden Zeitabläufen auch die oben vorgeschlagenen Zeitausreißerlösungen aufgeführt - einschließlich:
list(s)[0]
, John ‚s neue sequenzbasierte Lösung .random.sample(s, 1)
, dF. eklektische RNG-basierte Lösung .Code-Schnipsel für große Freude
Einschalten, einschalten, zeitlich festlegen:
Schnell veraltete zeitlose Timings
Erblicken! Sortiert nach schnellsten bis langsamsten Schnipsel:
Gesichtspflanzen für die ganze Familie
Es überrascht nicht, dass die manuelle Iteration mindestens doppelt so schnell bleibt wie die nächstschnellste Lösung. Obwohl sich die Lücke seit den Tagen von Bad Old Python 2.x verringert hat (in denen die manuelle Iteration mindestens viermal so schnell war), enttäuscht es den PEP 20- Fanatiker in mir, dass die ausführlichste Lösung die beste ist. Zumindest das Konvertieren eines Sets in eine Liste, um nur das erste Element des Sets zu extrahieren, ist so schrecklich wie erwartet. Danke Guido, möge sein Licht uns weiterhin führen.
Überraschenderweise ist die RNG-basierte Lösung absolut schrecklich. Listenkonvertierung ist schlecht, nimmt aber
random
wirklich den schrecklichen Saucen-Kuchen. Soviel zum Zufallszahlengott .Ich wünschte nur, die Amorphen würden
set.get_first()
bereits eine Methode für uns entwickeln. Wenn Sie dies lesen, sagen sie: "Bitte. Tun Sie etwas."quelle
next(iter(s))
das zweimal langsamer ist alsfor x in s: break
inCPython
. Ich meine das istCPython
. Es wird ungefähr 50-100 Mal (oder so ähnlich) langsamer sein als C oder Haskell, die das Gleiche tun (die meiste Zeit, insbesondere bei Iterationen, keine Eliminierung von Tail Calls und keinerlei Optimierungen). Das Verlieren einiger Mikrosekunden macht keinen wirklichen Unterschied. Denkst du nicht? Und es gibt auch PyPyBeachten Sie den folgenden Code, um einige Zeitangaben für die verschiedenen Ansätze bereitzustellen. Das get () ist meine benutzerdefinierte Ergänzung zu Pythons setobject.c, da es nur ein pop () ist, ohne das Element zu entfernen.
Die Ausgabe ist:
Dies bedeutet, dass die for / break- Lösung die schnellste ist (manchmal schneller als die benutzerdefinierte get () -Lösung).
quelle
for x in s
? "Für das Ergebnis der wird ein Iterator erstelltexpression_list
."s.remove()
in die die mischeniter
Beispiele beidefor
unditer
gehen katastrophal schlecht.Da Sie ein zufälliges Element möchten, funktioniert dies auch:
Die Dokumentation scheint die Leistung von nicht zu erwähnen
random.sample
. Nach einem wirklich schnellen empirischen Test mit einer riesigen Liste und einer riesigen Menge scheint es eine konstante Zeit für eine Liste zu sein, aber nicht für die Menge. Außerdem ist die Iteration über eine Menge nicht zufällig. Die Reihenfolge ist undefiniert, aber vorhersehbar:Wenn Zufälligkeit wichtig ist und Sie eine Reihe von Elementen in konstanter Zeit benötigen (große Mengen), würde ich diese zuerst verwenden
random.sample
und in eine Liste konvertieren:quelle
choice()
, da Python versucht, Ihren Satz zu indizieren, und das funktioniert nicht.Scheinbar der kompakteste (6 Symbole), wenn auch sehr langsame Weg, um ein gesetztes Element zu erhalten (ermöglicht durch PEP 3132 ):
Mit Python 3.5+ können Sie auch diesen Ausdruck mit 7 Symbolen verwenden (dank PEP 448 ):
Beide Optionen sind auf meinem Computer ungefähr 1000-mal langsamer als die For-Loop-Methode.
quelle
Ich benutze eine Dienstprogrammfunktion, die ich geschrieben habe. Sein Name ist etwas irreführend, weil er impliziert, dass es sich um einen zufälligen Gegenstand oder ähnliches handelt.
quelle
Nach @wr. Post, ich bekomme ähnliche Ergebnisse (für Python3.5)
Ausgabe:
Beim Ändern der zugrunde liegenden Menge (z. B. Aufruf von
remove()
) laufen die iterierbaren Beispiele (for
,iter
) jedoch schlecht :Ergebnisse in:
quelle
Was ich normalerweise für kleine Sammlungen mache, ist eine Art Parser / Konverter-Methode wie diese zu erstellen
Dann kann ich die neue Liste verwenden und über die Indexnummer zugreifen
Als Liste haben Sie alle anderen Methoden, mit denen Sie möglicherweise arbeiten müssen
quelle
list
anstatt eine Konvertermethode zu erstellen?Wie wäre es
s.copy().pop()
? Ich habe es nicht geplant, aber es sollte funktionieren und es ist einfach. Es funktioniert jedoch am besten für kleine Sets, da es das gesamte Set kopiert.quelle
Eine andere Möglichkeit besteht darin, ein Wörterbuch mit Werten zu verwenden, die Sie nicht interessieren. Z.B,
Sie können die Schlüssel als Satz behandeln, außer dass sie nur ein Array sind:
Ein Nebeneffekt dieser Auswahl ist, dass Ihr Code mit älteren Vorversionen
set
von Python abwärtskompatibel ist . Es ist vielleicht nicht die beste Antwort, aber es ist eine andere Option.Bearbeiten: Sie können sogar so etwas tun, um die Tatsache zu verbergen, dass Sie ein Diktat anstelle eines Arrays oder Sets verwendet haben:
quelle