Angenommen, ich habe eine Liste x
mit unbekannter Länge, aus der ich zufällig ein Element entfernen möchte, damit die Liste das Element danach nicht mehr enthält. Was ist der pythonischste Weg, dies zu tun?
Ich kann es eine ziemlich unhandliche combincation der Verwendung pop
, random.randint
und len
, und würde gerne kürzere oder schönere Lösungen sehen:
import random
x = [1,2,3,4,5,6]
x.pop(random.randint(0,len(x)-1))
Ich versuche, nacheinander zufällige Elemente aus einer Liste zu entfernen. (dh ein Element nach dem Zufallsprinzip einfügen und in ein Wörterbuch verschieben, ein anderes Element nach dem Zufallsprinzip einfügen und in ein anderes Wörterbuch verschieben, ...)
Beachten Sie, dass ich Python 2.6 verwende und über die Suchfunktion keine Lösungen gefunden habe.
Antworten:
Was Sie zu tun scheinen, sieht in erster Linie nicht sehr pythonisch aus. Sie sollten keine Inhalte aus der Mitte einer Liste entfernen, da Listen in allen mir bekannten Python-Implementierungen als Arrays implementiert sind. Dies ist also eine
O(n)
Operation.Wenn Sie diese Funktionalität wirklich als Teil eines Algorithmus benötigen, sollten Sie eine Datenstruktur wie die überprüfen, die ein
blist
effizientes Löschen aus der Mitte unterstützt.In reinem Python können Sie, wenn Sie keinen Zugriff auf die verbleibenden Elemente benötigen, zuerst die Liste mischen und dann darüber iterieren:
lst = [1,2,3] random.shuffle(lst) for x in lst: # ...
Wenn Sie den Rest wirklich brauchen (was meiner Meinung nach ein bisschen nach Code riecht), können Sie dies zumindest
pop()
am Ende der Liste tun (was schnell ist!):while lst: x = lst.pop() # do something with the element
Im Allgemeinen können Sie Ihre Programme häufig eleganter ausdrücken, wenn Sie einen funktionaleren Stil verwenden, anstatt den Status zu ändern (wie Sie es mit der Liste tun).
quelle
random.shuffle(x)
und dannx.pop()
? Ich verstehe nicht, wie man das "funktional" macht?zip
Sie eine Liste von (Diktat-, Zahlen-) Paaren abrufen. Sie haben etwas über mehrere Wörterbücher gesagt, von denen Sie jedes mit einer Zufallszahl verknüpfen möchten.zip
ist perfekt dafürSie werden nicht viel besser als das, aber hier ist eine leichte Verbesserung:
x.pop(random.randrange(len(x)))
Dokumentation zu
random.randrange()
:quelle
So entfernen Sie ein einzelnes Element mit zufälligem Index aus einer Liste, wenn die Reihenfolge der übrigen Listenelemente keine Rolle spielt:
import random L = [1,2,3,4,5,6] i = random.randrange(len(L)) # get random index L[i], L[-1] = L[-1], L[i] # swap with the last element x = L.pop() # pop last element O(1)
Der Swap wird verwendet, um das O (n) -Verhalten beim Löschen aus der Mitte einer Liste zu vermeiden.
quelle
Hier ist eine weitere Alternative: Warum mischen Sie nicht zuerst die Liste und beginnen dann, Elemente davon zu platzieren, bis keine Elemente mehr übrig sind? so was:
import random x = [1,2,3,4,5,6] random.shuffle(x) while x: p = x.pop() # do your stuff with p
quelle
[for p in x]
Ein Weg, dies zu tun, ist:
quelle
pop
Sie einen Namen auf das entfernte Element verweisen, mit diesem können Sie nicht.remove
ein linearer Scan der Liste erforderlich. Das ist schrecklich ineffizient im Vergleich zum Nachschlagen eines Index.Während ich nicht aus der Liste auftauchte, stieß ich bei Google auf diese Frage, als ich versuchte, X zufällige Elemente aus einer Liste ohne Duplikate abzurufen. Folgendes habe ich schließlich verwendet:
items = [1, 2, 3, 4, 5] items_needed = 2 from random import shuffle shuffle(items) for item in items[:items_needed]: print(item)
Dies kann etwas ineffizient sein, da Sie eine ganze Liste mischen, aber nur einen kleinen Teil davon verwenden, aber ich bin kein Optimierungsexperte, daher könnte ich mich irren.
quelle
random.sample(items, items_needed)
Ich weiß, dass dies eine alte Frage ist, aber nur zur Dokumentation:
Wenn Sie (die Person, die dieselbe Frage googelt) das tun, was Sie meiner Meinung nach tun, wählen Sie k zufällig eine Anzahl von Elementen aus einer Liste aus (wobei k <= len (Ihre Liste)), stellen Sie jedoch sicher, dass jedes Element nie mehr ausgewählt wird mehr als einmal (= Stichprobe ohne Ersatz) könnten Sie random.sample verwenden, wie es @ jf-sebastian vorschlägt. Aber ohne mehr über den Anwendungsfall zu wissen, weiß ich nicht, ob Sie dies benötigen.
quelle
trotz vielen Antworten Gebrauch was darauf hindeutet ,
random.shuffle(x)
undx.pop()
seine sehr langsam auf große Daten. und die für eine Liste von10000
Elementen erforderliche Zeit dauerte ungefähr,6 seconds
wenn das Mischen aktiviert wurde. Wenn Shuffle deaktiviert ist, war die Geschwindigkeit0.2s
Die schnellste Methode nach dem Testen aller oben genannten Methoden wurde von @jfs geschrieben
import random L = ['1',2,3,'4'...1000] #you can take mixed or pure list i = random.randrange(len(L)) # get random index L[i], L[-1] = L[-1], L[i] # swap with the last element x = L.pop() # pop last element O(1)
Zur Unterstützung meiner Behauptung hier ist das Zeitkomplexitätsdiagramm aus dieser Quelle
WENN die Liste keine Duplikate enthält,
Sie können Ihren Zweck auch mit Sets erreichen. Sobald die Liste zu festgelegten Duplikaten erstellt wurde, wird sie entfernt.
remove by value
undremove random
KostenO(1)
, dh sehr effizient. Dies ist die sauberste Methode, die ich mir vorstellen kann.L=set([1,2,3,4,5,6...]) #directly input the list to inbuilt function set() while 1: r=L.pop() #do something with r , r is random element of initial list L.
Im Gegensatz zu
lists
welcher Support-A+B
Option unterstützen Siesets
auchA-B (A minus B)
zusammen mitA+B (A union B)
undA.intersection(B,C,D)
. Sehr nützlich, wenn Sie logische Operationen an den Daten ausführen möchten.OPTIONAL
Wenn Sie Geschwindigkeit wünschen, wenn Operationen an Kopf und Ende der Liste ausgeführt werden, verwenden Sie Python Dequeue (Double Ended Queue), um meine Behauptung zu unterstützen. Ein Bild besteht aus tausend Wörtern.
quelle
Diese Antwort wurde freundlicherweise von @ niklas-b zur Verfügung gestellt :
" Sie möchten wahrscheinlich so etwas wie pypi.python.org/pypi/blist verwenden. "
So zitieren Sie die PYPI-Seite :
Man würde eine verminderte Leistung am Ende des Direktzugriffs / Zufallslaufs annehmen , da es sich um eine Datenstruktur "Kopie beim Schreiben" handelt. Dies verstößt gegen viele Anwendungsfallannahmen in Python-Listen. Gehen Sie daher vorsichtig damit um .
Wenn Ihr Hauptanwendungsfall jedoch darin besteht, etwas Seltsames und Unnatürliches mit einer Liste zu tun (wie im erzwungenen Beispiel von @OP oder meinem Problem mit der Python 2.6-FIFO-FIFO-Warteschlange mit Übergabe), passt dies gut zur Rechnung .
quelle