¿Por qué random.shuffle devuelve None?

88

¿Por qué random.shuffleregresa Noneen Python?

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

¿Cómo obtengo el valor barajado en lugar de None?

alvas
fuente
no un valor aleatorio sino una mezcla aleatoria de la lista.
alvas
3
Relacionado: las funciones sort () y reverse () no funcionan
Martijn Pieters

Respuestas:

157

random.shuffle()cambia la xlista en su lugar .

Los métodos de la API de Python que alteran una estructura en el lugar generalmente devuelven None, no la estructura de datos modificada.

Si desea crear una nueva lista aleatoria basada en una existente, donde la lista existente se mantiene en orden, puede usar random.sample()con la longitud completa de la entrada:

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

También puede usar sorted()con random.random()para una clave de clasificación:

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

pero esto invoca la clasificación (una operación O (NlogN)), mientras que el muestreo a la longitud de entrada solo toma operaciones O (N) (el mismo proceso que random.shuffle()se usa, intercambiando valores aleatorios de un grupo que se reduce).

Manifestación:

>>> 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']
Martijn Pieters
fuente
2
¿Está keyrealmente garantizado el uso de una función de valor aleatorio ? Algunos algoritmos de clasificación rápida fracasan si las comparaciones no son autoconsistentes. Puedo ver que esto funciona de cualquier manera, dependiendo de la implementación (decorate-sort-undecorate solo deberá aplicarse keyuna vez en cada elemento, por lo que estará bien definido).
torek
2
@torek: Python usa decorate-sort-undecorate al ordenar con un keyinvocable. Así que sí, está garantizado ya que a cada valor se le da su clave aleatoria exactamente una vez.
Martijn Pieters
35

Este método también funciona.

import random
shuffled = random.sample(original, len(original))
Acemad
fuente
8

Según los documentos :

Mezcla la secuencia x en su lugar. El argumento opcional aleatorio es una función de argumento 0 que devuelve un flotante aleatorio en [0.0, 1.0); por defecto, esta es la función aleatoria ().

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

¿Por qué realmente?

1. Eficiencia

shufflemodifica la lista en su lugar. Esto es bueno, porque copiar una lista grande sería una sobrecarga si ya no necesita la lista original.

2. Estilo pitónico

Según el principio "explícito es mejor que implícito" del estilo pitónico , devolver la lista sería una mala idea, porque entonces se podría pensar que es nueva aunque en realidad no lo es.

¡Pero no me gusta así!

Si usted no necesita una nueva lista, tendrá que escribir algo como

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

que es muy explícito. Si necesita este modismo con frecuencia, envuélvalo en una función shuffled(ver sorted) que devuelva new_x.

Lutz Prechelt
fuente
2

Tuve mi momento aha con este concepto como este:

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']
presencia ligera
fuente
Porque Python hace "copiar por valores" de forma predeterminada en lugar de pasar por referencia =) stackoverflow.com/a/986495/610569
alvas
2

Las API de Python que cambian la estructura en su lugar devuelven None como resultado.

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

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

from random import shuffle
print(shuffle(list))

Salida: ninguna

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

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

usuario3467537
fuente
0

Puede devolver la lista aleatoria utilizando random.sample()como explicaron otros. Funciona muestreando k elementos de la lista sin reemplazo . Entonces, si hay elementos duplicados en su lista, se tratarán de manera única.

>>> 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]
devsaw
fuente