Mengapa random.shuffle mengembalikan None?


90

Mengapa random.shufflekembali Nonedengan Python?

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

Bagaimana cara mendapatkan nilai yang diacak None?


bukan nilai acak tetapi pengacakan daftar secara acak.
alvas


Jawaban:


162

random.shuffle()mengubah xdaftar di tempat .

Metode Python API yang mengubah struktur di tempat biasanya mengembalikan None, bukan struktur data yang dimodifikasi.

Jika Anda ingin membuat daftar baru yang diacak secara acak berdasarkan daftar yang sudah ada, di mana daftar yang ada disimpan secara berurutan, Anda dapat menggunakan random.sample()dengan input lengkap:

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

Anda juga bisa menggunakan sorted()with random.random()untuk kunci penyortiran:

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

tetapi ini memanggil pengurutan (operasi O (NlogN)), sementara pengambilan sampel ke panjang input hanya membutuhkan operasi O (N) (proses yang sama seperti random.shuffle()yang digunakan, menukar nilai acak dari kumpulan menyusut).

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
Apakah menggunakan keyfungsi nilai acak benar- benar dijamin? Beberapa algoritme pengurutan cepat gagal jika perbandingan tidak konsisten. Saya dapat melihat ini bekerja dengan cara apa pun, tergantung pada implementasinya (decorate-sort-undecorate hanya perlu diterapkan keysekali pada setiap elemen sehingga akan terdefinisi dengan baik).
torek

2
@torek: Python menggunakan decorate-sort-undecorate saat menyortir dengan keycallable. Jadi ya, itu dijamin karena setiap nilai diberikan kunci acaknya tepat satu kali.
Martijn Pieters

37

Metode ini juga berhasil.

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

8

Menurut dokumen :

Kocok urutan x di tempatnya. Argumen opsional acak adalah fungsi 0-argumen yang mengembalikan float acak di [0.0, 1.0); secara default, ini adalah fungsi random ().

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

6

Kenapa benarkah?

1. Efisiensi

shufflemengubah daftar di tempat. Ini bagus, karena menyalin daftar yang besar akan menjadi overhead murni jika Anda tidak memerlukan daftar asli lagi.

2. Gaya pythonic

Menurut prinsip "eksplisit lebih baik daripada implisit" dari gaya pythonic , mengembalikan daftar akan menjadi ide yang buruk, karena kemudian orang mungkin berpikir itu adalah yang baru meskipun pada kenyataannya tidak.

Tapi saya tidak suka seperti ini!

Jika Anda memang membutuhkan daftar baru, Anda harus menulis sesuatu seperti

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

yang sangat eksplisit. Jika Anda sering membutuhkan idiom ini, bungkus dalam fungsi shuffled(lihat sorted) yang mengembalikan new_x.


2

Saya mengalami momen aha saya dengan konsep ini seperti ini:

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

Karena python melakukan "copy-by-values" secara default, bukan pass-by-reference =) stackoverflow.com/a/986495/610569
alvas

2

Python API yang mengubah struktur di tempatnya sendiri mengembalikan None sebagai keluaran.

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

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

from random import shuffle
print(shuffle(list))

Output: Tidak Ada

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

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


0

Anda dapat mengembalikan daftar yang diacak menggunakan random.sample()seperti yang dijelaskan oleh orang lain. Ini bekerja dengan mengambil sampel k elemen dari daftar tanpa penggantian . Jadi jika ada elemen duplikat dalam daftar Anda, mereka akan diperlakukan secara unik.

>>> 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]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.