Warum gibt random.shuffle None zurück?


86

Warum random.shufflekehrt man Nonein Python zurück?

>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> print shuffle(x)
None

Wie erhalte ich den gemischten Wert anstelle von None?


kein zufälliger Wert, sondern zufälliges Mischen der Liste.
Alvas


Antworten:


156

random.shuffle()ändert die xListe an Ort und Stelle .

Python-API-Methoden, die eine Struktur direkt ändern, geben im Allgemeinen Nonenicht die geänderte Datenstruktur zurück.

Wenn Sie eine neue zufällig gemischte Liste basierend auf einer vorhandenen Liste erstellen möchten, in der die vorhandene Liste in der richtigen Reihenfolge gehalten wird, können Sie sie random.sample()mit der gesamten Länge der Eingabe verwenden:

x = ['foo', 'bar', 'black', 'sheep']
random.sample(x, len(x))     

Sie können auch sorted()mit random.random()für einen Sortierschlüssel verwenden:

shuffled = sorted(x, key=lambda k: random.random())

Dies ruft jedoch die Sortierung auf (eine O (NlogN) -Operation), während das Abtasten auf die Eingabelänge nur O (N) -Operationen erfordert (der gleiche Prozess wie random.shuffle()der, bei dem zufällige Werte aus einem schrumpfenden Pool ausgetauscht werden).

Demo:

>>> import random
>>> x = ['foo', 'bar', 'black', 'sheep']
>>> random.sample(x, len(x))
['bar', 'sheep', 'black', 'foo']
>>> sorted(x, key=lambda k: random.random())
['sheep', 'foo', 'black', 'bar']
>>> x
['foo', 'bar', 'black', 'sheep']

2
Ist die Verwendung einer zufällig bewerteten keyFunktion wirklich garantiert? Einige schnelle Sortieralgorithmen fallen um, wenn Vergleiche nicht selbstkonsistent sind. Ich kann sehen, dass dies je nach Implementierung in beide Richtungen funktioniert (Decorate-Sort-Undecorate muss nur keyeinmal auf jedes Element angewendet werden, damit es genau definiert ist).
Torek

2
@torek: Python verwendet beim Sortieren mit einem keyaufrufbaren Element dekorieren-sortieren-undekorieren . Also ja, es ist garantiert, da jeder Wert genau einmal seinen Zufallsschlüssel erhält.
Martijn Pieters

35

Diese Methode funktioniert auch.

import random
shuffled = random.sample(original, len(original))

8

Laut Dokumentation :

Mische die Sequenz x an Ort und Stelle. Das optionale Argument random ist eine 0-Argument-Funktion, die einen zufälligen Float in [0.0, 1.0) zurückgibt. Standardmäßig ist dies die Funktion random ().

>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> shuffle(x)
>>> x
['bar', 'black', 'sheep', 'foo']

6

Warum eigentlich?

1. Effizienz

shuffleändert die Liste an Ort und Stelle. Das ist schön, denn das Kopieren einer großen Liste wäre ein reiner Aufwand, wenn Sie die ursprüngliche Liste nicht mehr benötigen.

2. Pythonischer Stil

Nach dem Prinzip "explizit ist besser als implizit" des pythonischen Stils wäre es eine schlechte Idee, die Liste zurückzugeben, da man dann denken könnte, es sei eine neue, obwohl dies tatsächlich nicht der Fall ist.

Aber ich mag es nicht so!

Wenn Sie noch eine frische Liste benötigen, haben Sie so etwas wie schreiben

new_x = list(x)  # make a copy
random.shuffle(new_x)

das ist schön explizit. Wenn Sie dieses Idiom häufig benötigen, schließen Sie es in eine Funktion shuffled(siehe sorted) ein, die zurückgibt new_x.


2

Ich hatte meinen Aha-Moment mit diesem Konzept wie folgt:

from random import shuffle
x = ['foo','black','sheep'] #original list
y = list(x) # an independent copy of the original
for i in range(5):
    print shuffle(y) # shuffles the original "in place" prints "None" return
    print x,y #prints original, and shuffled independent copy

>>>
None
['foo', 'black', 'sheep'] ['foo', 'black', 'sheep']
None
['foo', 'black', 'sheep'] ['black', 'foo', 'sheep']
None
['foo', 'black', 'sheep'] ['sheep', 'black', 'foo']
None
['foo', 'black', 'sheep'] ['black', 'foo', 'sheep']
None
['foo', 'black', 'sheep'] ['sheep', 'black', 'foo']

Weil Python standardmäßig "Copy-by-Values" anstelle von Pass-by-Reference ausführt
alvas

2

Python-APIs, die die Struktur selbst ändern, geben None als Ausgabe zurück.

list = [1,2,3,4,5,6,7,8]
print(list)

Ausgabe: [1, 2, 3, 4, 5, 6, 7, 8]

from random import shuffle
print(shuffle(list))

Ausgabe: Keine

from random import sample
print(sample(list, len(list)))

Ausgabe: [7, 3, 2, 4, 5, 6, 1, 8]


0

Sie können die gemischte Liste random.sample()wie von anderen erläutert zurückgeben. Es funktioniert, indem k Elemente aus der Liste ersatzlos abgetastet werden . Wenn Ihre Liste also doppelte Elemente enthält, werden diese eindeutig behandelt.

>>> l = [1,4,5,3,5]
>>> random.sample(l,len(l))
[4, 5, 5, 3, 1]
>>> random.sample(l,len(l)-1)
[4, 1, 5, 3]
>>> random.sample(l,len(l)-1)
[3, 5, 5, 1]
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.