Por que está random.shuffle
retornando None
em Python?
>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> print shuffle(x)
None
Como obtenho o valor embaralhado em vez de None
?
Por que está random.shuffle
retornando None
em Python?
>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> print shuffle(x)
None
Como obtenho o valor embaralhado em vez de None
?
Respostas:
random.shuffle()
muda a x
lista no local .
Os métodos da API Python que alteram uma estrutura local geralmente retornam None
, não a estrutura de dados modificada.
Se você quiser criar uma nova lista embaralhada aleatoriamente com base em uma existente, em que a lista existente é mantida em ordem, você pode usar random.sample()
com o comprimento total da entrada:
x = ['foo', 'bar', 'black', 'sheep']
random.sample(x, len(x))
Você também pode usar sorted()
com random.random()
para uma chave de classificação:
shuffled = sorted(x, key=lambda k: random.random())
mas isso invoca a classificação (uma operação O (NlogN)), enquanto a amostragem para o comprimento de entrada leva apenas O (N) operações (o mesmo processo que random.shuffle()
é usado, trocando valores aleatórios de um pool de encolhimento).
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']
key
função com valor aleatório é realmente garantido? Alguns algoritmos de classificação rápida falham se as comparações não forem autoconsistentes. Eu posso ver isso funcionando de qualquer maneira, dependendo da implementação (decorate-sort-undecorate só precisará ser aplicado key
uma vez em cada elemento, portanto, será bem definido).
key
chamável. Portanto, sim, é garantido que cada valor recebe sua chave aleatória exatamente uma vez.
De acordo com a documentação :
Embaralhe a sequência x no lugar. O argumento opcional random é uma função de 0 argumento que retorna um float aleatório em [0.0, 1.0); por padrão, esta é a função random ().
>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> shuffle(x)
>>> x
['bar', 'black', 'sheep', 'foo']
shuffle
modifica a lista no local. Isso é bom, porque copiar uma lista grande seria pura sobrecarga se você não precisar mais da lista original.
De acordo com o princípio "explícito é melhor do que implícito" do estilo pythônico , devolver a lista seria uma má ideia, porque então poderíamos pensar que é uma lista nova, embora na verdade não seja.
Se você não precisa de uma nova lista, você terá que escrever algo como
new_x = list(x) # make a copy
random.shuffle(new_x)
o que é bem explícito. Se você precisa desse idioma com freqüência, envolva-o em uma função shuffled
(consulte sorted
Recursos) que retorna new_x
.
Eu tive meu momento aha com este conceito assim:
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']
APIs Python que mudam a estrutura no local, retornam None como saída.
list = [1,2,3,4,5,6,7,8]
print(list)
Resultado: [1, 2, 3, 4, 5, 6, 7, 8]
from random import shuffle
print(shuffle(list))
Resultado: Nenhum
from random import sample
print(sample(list, len(list)))
Resultado: [7, 3, 2, 4, 5, 6, 1, 8]
Você pode retornar a lista embaralhada usando random.sample()
conforme explicado por outros. Ele funciona por amostragem de k elementos da lista sem substituição . Portanto, se houver elementos duplicados em sua lista, eles serão tratados de forma exclusiva.
>>> 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]