Perché random.shuffle restituisce None?


90

Perché random.shuffleritorna Nonein Python?

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

Come ottengo il valore mescolato invece di None?


non un valore casuale ma un mescolamento casuale della lista.
alvas


Risposte:


162

random.shuffle()cambia l' xelenco in posizione .

I metodi API Python che alterano una struttura sul posto generalmente restituiscono None, non la struttura dei dati modificata.

Se si desidera creare un nuovo elenco mescolato in modo casuale basato su uno esistente, in cui l'elenco esistente viene mantenuto in ordine, è possibile utilizzare random.sample()con l'intera lunghezza dell'input:

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

Puoi anche usare sorted()con random.random()per una chiave di ordinamento:

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

ma questo richiama l'ordinamento (un'operazione O (NlogN)), mentre il campionamento alla lunghezza di input richiede solo operazioni O (N) (lo stesso processo random.shuffle()utilizzato, scambiando valori casuali da un pool di riduzione).

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
L'utilizzo di una keyfunzione a valori casuali è davvero garantito? Alcuni algoritmi di ordinamento rapido cadono se i confronti non sono auto-coerenti. Posso vedere che funziona in entrambi i modi, a seconda dell'implementazione (decor-sort-undecorate dovrà essere applicato solo keyuna volta su ogni elemento, quindi sarà ben definito).
torek

2
@torek: Python usa decorate-sort-undecorate quando ordina con un keycallable. Quindi sì, è garantito poiché a ciascun valore viene assegnata la chiave casuale esattamente una volta.
Martijn Pieters

37

Anche questo metodo funziona.

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

8

Secondo i documenti :

Mescola la sequenza x in posizione. L'argomento opzionale random è una funzione con 0 argomenti che restituisce un float casuale in [0.0, 1.0); per impostazione predefinita, questa è la funzione random ().

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

6

Perché davvero?

1. Efficienza

shufflemodifica l'elenco in atto. Questo è bello, perché copiare un elenco di grandi dimensioni sarebbe un puro sovraccarico se non hai più bisogno dell'elenco originale.

2. Stile pitonico

Secondo il principio "esplicito è meglio che implicito" dello stile pitonico , restituire l'elenco sarebbe una cattiva idea, perché allora si potrebbe pensare che sia nuovo, anche se in realtà non lo è.

Ma non mi piace così!

Se non bisogno di una lista fresca, si dovrà scrivere qualcosa di simile

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

che è piacevolmente esplicito. Se hai bisogno di questo idioma frequentemente, racchiudilo in una funzione shuffled(vedi sorted) che restituisce new_x.


2

Ho avuto il mio aha momento con questo concetto in questo modo:

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']

Perché Python fa "copia-by-valori" di default al posto di passaggio per riferimento =) stackoverflow.com/a/986495/610569
alvas

2

Le API Python che modificano la struttura in posizione restituiscono None come output.

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

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

from random import shuffle
print(shuffle(list))

Uscita: nessuno

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

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


0

È possibile restituire l'elenco mescolato utilizzando random.sample()come spiegato da altri. Funziona campionando k elementi dall'elenco senza sostituzione . Pertanto, se nell'elenco sono presenti elementi duplicati, verranno trattati in modo univoco.

>>> 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]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.