Mengacak daftar objek

771

Saya memiliki daftar objek dan saya ingin mengocoknya. Saya pikir saya bisa menggunakan random.shufflemetode ini, tetapi ini tampaknya gagal ketika daftar objek. Apakah ada metode untuk mengocok objek atau cara lain untuk mengatasi ini?

import random

class A:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1, a2]

print(random.shuffle(b))

Ini akan gagal.

utdiscant
sumber
6
Bisakah Anda memberi contoh bagaimana itu gagal? random.shuffle harus bekerja dengan jenis objek di dalam daftar.
bayer
3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. instance di 0xb7df9e6c>, <__ main __. instance di 0xb7df9e2c>]>> >> print random.shuffle (b) Tidak ada
utdiscant
135
Seperti yang dinyatakan di bawah ini, random.shuffle tidak mengembalikan daftar acak baru; itu mengocok daftar di tempat. Jadi Anda tidak boleh mengatakan "print random.shuffle (b)" dan sebagai gantinya harus melakukan pengocokan pada satu baris dan mencetak b pada baris berikutnya.
Eli Courtwright
Jika Anda mencoba mengocok array numpy, lihat jawaban saya di bawah ini.
Gordon Bean
1
apakah ada opsi yang tidak mengubah array asli tetapi mengembalikan array acak baru?
Charlie Parker

Jawaban:

1241

random.shuffleharus bekerja. Berikut ini contoh, di mana objek adalah daftar:

from random import shuffle
x = [[i] for i in range(10)]
shuffle(x)

# print(x)  gives  [[9], [2], [7], [0], [4], [5], [3], [1], [8], [6]]
# of course your results will vary

Perhatikan bahwa shuffle berfungsi di tempatnya , dan mengembalikan None.

Tom10
sumber
1
@ Seokhoonlee Tidak. Ini adalah generator nomor pseduo-acak yang, jika mungkin, diunggulkan oleh sumber keacakan nyata dari OS. Untuk semua tujuan kecuali kriptografi itu adalah acak "cukup". Ini dituangkan secara rinci dalam randomdokumentasi modul .
dimo414
2
gunakan clone untuk daftar baru
Mohammad Mahdi KouchakYazdi
8
apakah ada opsi yang tidak mengubah array asli tetapi mengembalikan array acak baru?
Charlie Parker
5
@CharlieParker: Bukan yang saya tahu. Anda bisa menggunakan random.sample(x, len(x))atau hanya menyalinnya shufflesaja. Untuk list.sortyang memiliki masalah serupa, ada sekarang list.sorted, tetapi tidak ada varian serupa untuk shuffle.
Tom10
6
@ seokhonlee untuk keacakan crypto-secure, gunakan from random import SystemRandomsebagai gantinya; tambah cryptorand = SystemRandom()dan ubah baris 3 menjadicryptorand.shuffle(x)
ramban
115

Ketika Anda mengetahui pengocokan di tempat adalah masalahnya. Saya juga sering mengalami masalah, dan sepertinya sering lupa cara menyalin daftar juga. Menggunakansample(a, len(a)) adalah solusinya, menggunakan len(a)sebagai ukuran sampel. Lihat https://docs.python.org/3.6/library/random.html#random.sample untuk dokumentasi Python.

Berikut ini adalah versi sederhana penggunaan random.sample()yang mengembalikan hasil yang diacak sebagai daftar baru.

import random

a = range(5)
b = random.sample(a, len(a))
print a, b, "two list same:", a == b
# print: [0, 1, 2, 3, 4] [2, 1, 3, 4, 0] two list same: False

# The function sample allows no duplicates.
# Result can be smaller but not larger than the input.
a = range(555)
b = random.sample(a, len(a))
print "no duplicates:", a == list(set(b))

try:
    random.sample(a, len(a) + 1)
except ValueError as e:
    print "Nope!", e

# print: no duplicates: True
# print: Nope! sample larger than population
Ted
sumber
apakah ada opsi yang tidak mengubah array asli tetapi mengembalikan array acak baru?
Charlie Parker
cukup salin daftar @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(ganti; dengan baris baru)
fjsj
old[:]juga bisa melakukan salinan dangkal untuk daftar old.
Xiao
sample()sangat membantu untuk membuat prototipe analisis data. sample(data, 2)untuk mengatur kode lem pipa, kemudian "melebarkannya" secara bertahap, hingga len(data).
Katrin Leinweber
58

Butuh beberapa waktu untuk mendapatkannya juga. Tetapi dokumentasi untuk shuffle sangat jelas:

daftar acak x di tempat ; return Tidak ada.

Jadi kamu tidak seharusnya print(random.shuffle(b)). Sebaliknya lakukan random.shuffle(b)dan kemudian print(b).

Ohad Cohen
sumber
44
#!/usr/bin/python3

import random

s=list(range(5))
random.shuffle(s) # << shuffle before print or assignment
print(s)

# print: [2, 4, 1, 3, 0]
Michael
sumber
31

Jika Anda sudah menggunakan numpy (sangat populer untuk aplikasi ilmiah dan finansial), Anda dapat menyimpan sendiri impor.

import numpy as np    
np.random.shuffle(b)
print(b)

http://docs.scipy.org/doc/numpy/reference/generated/numpy.random.shuffle.html

fantabolous
sumber
Yang saya sukai dari jawaban ini adalah saya bisa mengontrol seed acak dengan numpy. Saya yakin ada cara untuk melakukannya dalam modul acak tetapi itu tidak jelas bagi saya sekarang ... yang berarti saya perlu membaca lebih lanjut.
VanBantam
25
>>> import random
>>> a = ['hi','world','cat','dog']
>>> random.shuffle(a,random.random)
>>> a
['hi', 'cat', 'dog', 'world']

Ini bekerja dengan baik untuk saya. Pastikan untuk mengatur metode acak.

Dan Lorenc
sumber
Masih tidak berfungsi untuk saya, lihat contoh kode saya di pertanyaan yang diedit.
utdiscant
4
Parameter kedua default ke random.random. Sangat aman untuk meninggalkannya.
cbare
3
@alvas random.shuffle (a) tidak mengembalikan apa pun yaitu mengembalikan Tidak ada. Jadi, Anda harus memeriksa nilai tidak mengembalikan.
sonus21
15

Jika Anda memiliki beberapa daftar, Anda mungkin ingin menentukan permutasi (cara Anda mengacak daftar / mengatur ulang item dalam daftar) terlebih dahulu dan kemudian menerapkannya ke semua daftar:

import random

perm = list(range(len(list_one)))
random.shuffle(perm)
list_one = [list_one[index] for index in perm]
list_two = [list_two[index] for index in perm]

Numpy / Scipy

Jika daftar Anda adalah array numpy, itu lebih sederhana:

import numpy as np

perm = np.random.permutation(len(list_one))
list_one = list_one[perm]
list_two = list_two[perm]

mpu

Saya telah membuat paket utilitas kecil mpuyang memiliki consistent_shufflefungsi:

import mpu

# Necessary if you want consistent results
import random
random.seed(8)

# Define example lists
list_one = [1,2,3]
list_two = ['a', 'b', 'c']

# Call the function
list_one, list_two = mpu.consistent_shuffle(list_one, list_two)

Catatan yang mpu.consistent_shufflemengambil sejumlah argumen sewenang-wenang. Jadi, Anda juga dapat mengacak tiga daftar atau lebih dengannya.

Martin Thoma
sumber
10
from random import random
my_list = range(10)
shuffled_list = sorted(my_list, key=lambda x: random())

Alternatif ini mungkin berguna untuk beberapa aplikasi di mana Anda ingin menukar fungsi pemesanan.

Jeff
sumber
Juga, perhatikan bahwa terima kasih sorted, ini adalah pengocokan fungsional (jika Anda menyukai hal semacam itu).
Inaimathi
1
Ini tidak benar-benar mendistribusikan nilai secara acak karena stabilitas Timsort. (Nilai dengan kunci yang sama dibiarkan dalam urutan aslinya.) EDIT: Saya kira itu tidak masalah karena risiko tabrakan dengan pelampung 64-bit sangat minim.
Mateen Ulhaq
10

Dalam beberapa kasus saat menggunakan array numpy, menggunakan random.shuffle data duplikat yang dibuat dalam array.

Alternatifnya adalah menggunakan numpy.random.shuffle. Jika Anda sudah menggunakan numpy, ini adalah metode yang lebih disukai daripada generik random.shuffle.

numpy.random.shuffle

Contoh

>>> import numpy as np
>>> import random

Menggunakan random.shuffle:

>>> foo = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> foo

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])


>>> random.shuffle(foo)
>>> foo

array([[1, 2, 3],
       [1, 2, 3],
       [4, 5, 6]])

Menggunakan numpy.random.shuffle:

>>> foo = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> foo

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])


>>> np.random.shuffle(foo)
>>> foo

array([[1, 2, 3],
       [7, 8, 9],
       [4, 5, 6]])
Gordon Bean
sumber
1
Juga, numpy.random.permutationmungkin menarik: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Gordon Bean
Apakah Anda memiliki contoh data duplikat yang dibuat dalam array saat menggunakan random.shuffle?
nurettin
Ya - itu termasuk dalam jawaban saya. Lihat bagian berjudul "Contoh". ;)
Gordon Bean
Namun, saya melihat tiga elemen dan berpikir itu sama. Nice find
nurettin
1
random.shuffledokumentasi harus berteriak Jangan gunakan dengan array numpy
winterlight
10

Untuk one-liners, gunakan random.sample(list_to_be_shuffled, length_of_the_list)dengan contoh:

import random
random.sample(list(range(10)), 10)

output: [2, 9, 7, 8, 3, 0, 4, 1, 6, 5]

weiyixie
sumber
6

'print func (foo)' akan mencetak nilai balik dari 'func' ketika dipanggil dengan 'foo'. 'shuffle' tetapi tidak memiliki None sebagai jenis pengembaliannya, karena daftar akan dimodifikasi di tempat, maka tidak mencetak apa pun. Penanganan masalah:

# shuffle the list in place 
random.shuffle(b)

# print it
print(b)

Jika Anda lebih menyukai gaya pemrograman fungsional, Anda mungkin ingin membuat fungsi wrapper berikut:

def myshuffle(ls):
    random.shuffle(ls)
    return ls
JonDoe
sumber
2
Karena ini meneruskan referensi ke daftar, aslinya diubah. Anda mungkin ingin menyalin daftar sebelum mengocok menggunakan deepcopy
shivram.ss
@ shivram.ss Dalam hal ini, Anda akan menginginkan sesuatu seperti random.sample(ls, len(ls))jika Anda benar-benar ingin turun rute itu.
Arda Xi
4

Seseorang dapat mendefinisikan fungsi yang disebut shuffled(dalam arti yang sama sortvs sorted)

def shuffled(x):
    import random
    y = x[:]
    random.shuffle(y)
    return y

x = shuffled([1, 2, 3, 4])
print x
malbarbo
sumber
3
import random

class a:
    foo = "bar"

a1 = a()
a2 = a()
a3 = a()
a4 = a()
b = [a1,a2,a3,a4]

random.shuffle(b)
print(b)

shuffle sudah ada, jadi jangan cetak hasil, yang ada None, tetapi daftar.

ravi tanwar
sumber
1

Anda bisa melakukannya untuk ini:

>>> A = ['r','a','n','d','o','m']
>>> B = [1,2,3,4,5,6]
>>> import random
>>> random.sample(A+B, len(A+B))
[3, 'r', 4, 'n', 6, 5, 'm', 2, 1, 'a', 'o', 'd']

jika Anda ingin kembali ke dua daftar, Anda kemudian membagi daftar panjang ini menjadi dua.

Kiriloff
sumber
1

Anda bisa membangun fungsi yang menggunakan daftar sebagai parameter dan mengembalikan versi daftar yang diacak:

from random import *

def listshuffler(inputlist):
    for i in range(len(inputlist)):
        swap = randint(0,len(inputlist)-1)
        temp = inputlist[swap]
        inputlist[swap] = inputlist[i]
        inputlist[i] = temp
    return inputlist
pengguna8327014
sumber
1
""" to shuffle random, set random= True """

def shuffle(x,random=False):
     shuffled = []
     ma = x
     if random == True:
         rando = [ma[i] for i in np.random.randint(0,len(ma),len(ma))]
         return rando
     if random == False:
          for i in range(len(ma)):
          ave = len(ma)//3
          if i < ave:
             shuffled.append(ma[i+ave])
          else:
             shuffled.append(ma[i-ave])    
     return shuffled
Josh Anish
sumber
pengantar atau penjelasan kecil akan sangat membantu?
kacase
fungsi ini sangat membantu untuk kegiatan pengacakan, bayangkan Anda harus mengacak daftar angka untuk tiga kali dan dalam tiga kali Anda memerlukan pengacakan acak untuk terjadi kemudian hanya mengubah argumen acak ke True lain jika Anda tidak memerlukan keacakan dan Anda ingin Agar pengocokan yang sama untuk dilestarikan maka jangan membuat perubahan, jalankan saja kodenya.
Josh Anish
Karena tidak ada kasus penggunaan di mana pemanggil fungsi ini akan memutuskan pada saat runtime apakah ia menginginkan acak atau non-acak, fungsi ini harus dibagi menjadi dua.
toolforger
Tidak ada deskripsi apa yang seharusnya dilakukan shuffle non-acak. (Pada garis singgung, itu bukan jawaban jadi pertanyaan, sehingga tidak melayani tujuan Stack Overflow.)
toolforger
1

Anda bisa menggunakan shuffle atau sampel. keduanya berasal dari modul acak.

import random
def shuffle(arr1):
    n=len(arr1)
    b=random.sample(arr1,n)
    return b

ATAU

import random
def shuffle(arr1):
    random.shuffle(arr1)
    return arr1
ravi tanwar
sumber
0

Pastikan Anda tidak menamai file sumber Anda random.py, dan bahwa tidak ada file di direktori kerja Anda yang disebut random.pyc .. dapat menyebabkan program Anda mencoba dan mengimpor file random.py lokal Anda alih-alih modul ular sanca. .

pengguna3298224
sumber
0
def shuffle(_list):
    if not _list == []:
        import random
        list2 = []
        while _list != []:
            card = random.choice(_list)
            _list.remove(card)
            list2.append(card)
        while list2 != []:
            card1 = list2[0]
            list2.remove(card1)
            _list.append(card1)
        return _list
Pogramist
sumber
Fungsi ini dapat membantu Anda jika Anda tidak ingin menggunakan modul acak
Pogramist
Solusi ini tidak hanya verbose tetapi tidak efisien (runtime sebanding dengan kuadrat ukuran daftar).
toolforger
Loop kedua dapat diganti dengan _list.extend(list2), yang lebih ringkas DAN lebih efisien.
toolforger
Fungsi Python yang memodifikasi parameter tidak boleh mengembalikan hasil. Ini hanya sebuah konvensi, tetapi yang bermanfaat: Orang sering tidak memiliki waktu untuk melihat implementasi semua fungsi yang mereka panggil, jadi siapa pun yang hanya melihat nama fungsi Anda dan bahwa hasilnya akan sangat terkejut melihat fungsinya. perbarui parameternya.
toolforger
0
import random
class a:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1.foo,a2.foo]
random.shuffle(b)
Xavier
sumber
-1

Proses pengocokan adalah "dengan penggantian" , sehingga terjadinya setiap item dapat berubah! Setidaknya ketika ketika item dalam daftar Anda juga daftar.

Misalnya,

ml = [[0], [1]] * 10

Setelah,

random.shuffle(ml)

Jumlah [0] mungkin 9 atau 8, tetapi tidak tepat 10.

Gatsby
sumber
-1

Paket: Tulis shuffle tanpa bergantung pada perpustakaan untuk melakukan pengangkatan berat. Contoh: Buka daftar dari awal mulai dengan elemen 0; cari posisi acak baru untuk itu, katakan 6, masukkan nilai 0 di nilai 6 dan 6 di 0. Pindah ke elemen 1 dan ulangi proses ini, dan seterusnya melalui sisa daftar

import random
iteration = random.randint(2, 100)
temp_var = 0
while iteration > 0:

    for i in range(1, len(my_list)): # have to use range with len()
        for j in range(1, len(my_list) - i):
            # Using temp_var as my place holder so I don't lose values
            temp_var = my_list[i]
            my_list[i] = my_list[j]
            my_list[j] = temp_var

        iteration -= 1
Enber
sumber
Anda dapat menukar variabel dengan python seperti ini:my_list[i], my_list[j] = my_list[j], my_list[i]
Karolis Ryselis
-2

Ini bekerja dengan baik. Saya mencoba di sini dengan fungsi sebagai objek daftar:

    from random import shuffle

    def foo1():
        print "foo1",

    def foo2():
        print "foo2",

    def foo3():
        print "foo3",

    A=[foo1,foo2,foo3]

    for x in A:
        x()

    print "\r"

    shuffle(A)
    for y in A:
        y()

Mencetak: foo1 foo2 foo3 foo2 foo3 foo1 (foo di baris terakhir memiliki urutan acak)

Stefan Gruenwald
sumber