Xáo trộn một danh sách các đối tượng


770

Tôi có một danh sách các đối tượng và tôi muốn xáo trộn chúng. Tôi nghĩ rằng tôi có thể sử dụng random.shufflephương thức này, nhưng điều này dường như thất bại khi danh sách là các đối tượng. Có một phương pháp để xáo trộn các đối tượng hoặc cách khác xung quanh điều này?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

Điều này sẽ thất bại.


6
Bạn có thể cho một ví dụ làm thế nào nó thất bại? Random.shuffle nên hoạt động bất biến đối với loại đối tượng trong danh sách.
bayer

3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ chính __. >> in random.shuffle (b) Không
utdiscant

135
Như đã nêu dưới đây, Random.shuffle không trả về một danh sách xáo trộn mới; nó xáo trộn danh sách tại chỗ. Vì vậy, bạn không nên nói "in Random.shuffle (b)" và thay vào đó nên thực hiện xáo trộn trên một dòng và in b trên dòng tiếp theo.
Eli Courtwright

Nếu bạn đang cố gắng xáo trộn các mảng numpy, hãy xem câu trả lời của tôi dưới đây.
Gordon Bean

1
Có một tùy chọn không làm thay đổi mảng ban đầu mà trả về một mảng được xáo trộn mới không?
Charlie Parker

Câu trả lời:


1241

random.shufflenên làm việc. Đây là một ví dụ, trong đó các đối tượng là danh sách:

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

Lưu ý rằng shuffle hoạt động tại chỗ và trả về Không.


1
@seokhoonlee Cả. Nó là một trình tạo số ngẫu nhiên pseduo, khi có thể, được tạo ra bởi một nguồn ngẫu nhiên thực sự từ HĐH. Đối với tất cả các mục đích ngoại trừ mật mã, nó là "đủ" ngẫu nhiên. Điều này được trình bày chi tiết trong randomtài liệu của mô-đun .
dimo414

2
sử dụng bản sao cho một danh sách mới
Mohammad Mahdi KouchakYazdi

8
Có một tùy chọn không làm thay đổi mảng ban đầu mà trả về một mảng được xáo trộn mới không?
Charlie Parker

5
@CharlieParker: Không phải tôi biết. Bạn có thể sử dụng random.sample(x, len(x))hoặc chỉ tạo một bản sao và shuffleđó. Đối với list.sortvấn đề tương tự, hiện tại list.sorted, nhưng không có biến thể tương tự shuffle.
tom10

6
@seokhonlee cho tính ngẫu nhiên an toàn của tiền điện tử, from random import SystemRandomthay vào đó hãy sử dụng ; thêm cryptorand = SystemRandom()và thay đổi hàng 3 thànhcryptorand.shuffle(x)
ngay từ

115

Khi bạn học được sự xáo trộn tại chỗ là vấn đề. Tôi cũng gặp vấn đề thường xuyên và dường như cũng quên cách sao chép danh sách. Sử dụng sample(a, len(a))là giải pháp, sử dụng len(a)như kích thước mẫu. Xem https://docs.python.org/3.6/l Library / brandom.html # brandom.sample để biết tài liệu Python.

Đây là một phiên bản đơn giản sử dụng random.sample()trả về kết quả được xáo trộn dưới dạng một danh sách mới.

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

Có một tùy chọn không làm thay đổi mảng ban đầu mà trả về một mảng được xáo trộn mới không?
Charlie Parker

chỉ cần sao chép danh sách @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(thay thế; bằng dòng mới)
fjsj

old[:]cũng có thể làm một bản sao nông cho danh sách old.
Xiao

sample()đặc biệt hữu ích cho việc tạo mẫu phân tích dữ liệu. sample(data, 2)để thiết lập mã keo của một đường ống, sau đó "mở rộng" nó theo từng bước len(data).
Katrin Leinweber

58

Tôi cũng mất một thời gian để có được điều đó. Nhưng tài liệu cho shuffle rất rõ ràng:

danh sách xáo trộn x tại chỗ ; Trả lại Không có.

Vì vậy, bạn không nên print(random.shuffle(b)). Thay vào đó hãy làm random.shuffle(b)và sau đó print(b).


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]

31

Nếu bạn tình cờ sử dụng numpy (rất phổ biến cho các ứng dụng khoa học và tài chính), bạn có thể tiết kiệm cho mình một lần nhập.

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

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


Điều tôi thích về câu trả lời này là tôi có thể kiểm soát hạt giống ngẫu nhiên trong numpy. Tôi cá là có một cách để làm điều đó trong mô-đun ngẫu nhiên nhưng điều đó không rõ ràng với tôi ngay bây giờ ... điều đó có nghĩa là tôi cần đọc thêm.
VanBantam

25
>>> import random
>>> a = ['hi','world','cat','dog']
>>> random.shuffle(a,random.random)
>>> a
['hi', 'cat', 'dog', 'world']

Việc này ổn với tôi. Hãy chắc chắn để đặt phương thức ngẫu nhiên.


Vẫn không làm việc cho tôi, xem mã ví dụ của tôi trong câu hỏi được chỉnh sửa.
utdiscant

4
Tham số thứ hai mặc định là Random.random. Nó hoàn toàn an toàn để bỏ nó ra.
cbare

3
@alvas Random.shuffle (a) không trả lại bất kỳ thứ gì, tức là nó không trả về. Vì vậy, bạn phải kiểm tra một giá trị không trả lại.
sonus21

15

Nếu bạn có nhiều danh sách, trước tiên bạn có thể muốn xác định hoán vị (cách bạn xáo trộn danh sách / sắp xếp lại các mục trong danh sách) và sau đó áp dụng nó cho tất cả các danh sách:

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

Nếu danh sách của bạn là mảng numpy, nó đơn giản hơn:

import numpy as np

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

mpu

Tôi đã tạo gói tiện ích nhỏ mpuconsistent_shufflechức năng:

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)

Lưu ý rằng mpu.consistent_shuffle có một số lượng các đối số tùy ý. Vì vậy, bạn cũng có thể xáo trộn ba hoặc nhiều danh sách với nó.


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

Sự thay thế này có thể hữu ích cho một số ứng dụng mà bạn muốn trao đổi chức năng đặt hàng.


Ngoài ra, lưu ý rằng nhờ sorted, đây là một sự xáo trộn chức năng (nếu bạn thuộc loại đó).
Inaimathi

1
Điều này không thực sự phân phối ngẫu nhiên các giá trị do tính ổn định của Timsort. (Các giá trị có cùng khóa được để lại theo thứ tự ban đầu.) EDIT: Tôi cho rằng điều đó không quan trọng vì nguy cơ va chạm với phao 64 bit là khá nhỏ.
Mateen Ulhaq

10

Trong một số trường hợp khi sử dụng mảng numpy, sử dụng random.shuffle dữ liệu trùng lặp được tạo trong mảng.

Một cách khác là sử dụng numpy.random.shuffle. Nếu bạn đang làm việc với numpy, đây là phương pháp ưa thích hơn chung chungrandom.shuffle .

numpy.random.shuffle

Thí dụ

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

Sử dụng 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]])

Sử dụng 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]])

1
Ngoài ra, numpy.random.permutationcó thể được quan tâm: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Gordon Bean

Bạn có một ví dụ về dữ liệu trùng lặp được tạo trong một mảng khi sử dụng Random.shuffle không?
Nurettin

Có - nó bao gồm trong câu trả lời của tôi. Xem phần có tên "Ví dụ". ;)
Gordon Bean

Nevermind, tôi thấy ba yếu tố và nghĩ rằng nó là như nhau. Tìm thấy tốt đẹp
Nurettin

1
random.shuffletài liệu nên hét Không sử dụng với mảng numpy
ánh sáng mùa đông

10

Đối với một lớp lót, sử dụng random.sample(list_to_be_shuffled, length_of_the_list)với một ví dụ:

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

đầu ra: [2, 9, 7, 8, 3, 0, 4, 1, 6, 5]


6

'print func (foo)' sẽ in giá trị trả về của 'func' khi được gọi bằng 'foo'. 'shuffle' tuy nhiên không có kiểu nào là kiểu trả về của nó, vì danh sách sẽ được sửa đổi tại chỗ, do đó nó không in gì cả. Cách giải quyết:

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

# print it
print(b)

Nếu bạn thích phong cách lập trình chức năng hơn, bạn có thể muốn thực hiện chức năng trình bao bọc sau:

def myshuffle(ls):
    random.shuffle(ls)
    return ls

2
Vì điều này vượt qua một tham chiếu đến danh sách, bản gốc được sửa đổi. Bạn có thể muốn sao chép danh sách trước khi xáo trộn bằng cách sử dụng deepcopy
shivram.ss

@ shivram.ss Trong trường hợp này, bạn sẽ muốn một cái gì đó giống như random.sample(ls, len(ls))nếu bạn thực sự muốn đi theo tuyến đường đó.
Arda Xi

4

Người ta có thể định nghĩa một hàm được gọi shuffled(theo cùng nghĩa sortvới vs sorted)

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

x = shuffled([1, 2, 3, 4])
print x

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 là tại chỗ, vì vậy không in kết quả, đó là None, nhưng danh sách.


1

Bạn có thể làm điều này:

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

nếu bạn muốn quay lại hai danh sách, sau đó bạn chia danh sách dài này thành hai danh sách.


1

bạn có thể xây dựng một hàm lấy danh sách làm tham số và trả về phiên bản được xáo trộn của danh sách:

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

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

một lời giới thiệu hoặc giải thích nhỏ sẽ hữu ích?
kacase

Hàm này rất hữu ích cho hoạt động xáo trộn, hãy tưởng tượng bạn phải xáo trộn danh sách các số trong ba lần và trong ba lần bạn yêu cầu xáo trộn ngẫu nhiên xảy ra, sau đó chỉ cần chuyển đối số ngẫu nhiên thành True khác nếu bạn không yêu cầu ngẫu nhiên và bạn muốn cùng một thứ tự xáo trộn được bảo tồn sau đó không thực hiện bất kỳ thay đổi nào, chỉ cần chạy mã.
Josh Anish

Vì không có trường hợp sử dụng nào mà người gọi hàm này sẽ quyết định trong thời gian chạy cho dù anh ta muốn ngẫu nhiên hay ngẫu nhiên không ngẫu nhiên, nên hàm này nên được chia thành hai.
toolforger

Không có mô tả những gì shuffle không ngẫu nhiên phải làm. (Trên một tiếp tuyến, nó không phải là một câu trả lời cho câu hỏi, vì vậy nó không phục vụ mục đích của Stack Overflow.)
toolforger

1

bạn có thể sử dụng shuffle hoặc mẫu. cả hai đều đến từ mô-đun ngẫu nhiên.

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

HOẶC LÀ

import random
def shuffle(arr1):
    random.shuffle(arr1)
    return arr1

0

Hãy chắc chắn rằng bạn không đặt tên tệp nguồn ngẫu nhiên của mình và không có tệp nào trong thư mục làm việc của bạn được gọi là Random.pyc .. có thể khiến chương trình của bạn thử và nhập tệp ngẫu nhiên cục bộ thay vì mô-đun ngẫu nhiên của pythons .


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

Chức năng này có thể giúp bạn nếu bạn không muốn sử dụng mô-đun ngẫu nhiên
Pogramist

Giải pháp này không chỉ dài dòng mà không hiệu quả (thời gian chạy tỷ lệ với bình phương kích thước danh sách).
toolforger

Vòng lặp thứ hai có thể được thay thế bằng _list.extend(list2), vòng lặp ngắn gọn và hiệu quả hơn.
toolforger

Hàm Python sửa đổi một tham số sẽ không bao giờ trả về kết quả. Đó chỉ là một quy ước, nhưng là một điều hữu ích: Mọi người thường thiếu thời gian để xem xét việc thực hiện tất cả các chức năng mà họ gọi, vì vậy bất kỳ ai chỉ nhìn thấy tên chức năng của bạn và kết quả sẽ rất ngạc nhiên khi thấy chức năng này cập nhật tham số của nó.
toolforger

0
import random
class a:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1.foo,a2.foo]
random.shuffle(b)

-1

Quá trình xáo trộn là "với sự thay thế" , vì vậy sự xuất hiện của từng mặt hàng có thể thay đổi! Ít nhất là khi các mục trong danh sách của bạn cũng là danh sách.

Ví dụ,

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

Sau,

random.shuffle(ml)

Số [0] có thể là 9 hoặc 8, nhưng không chính xác là 10.


-1

Kế hoạch: Viết ra shuffle mà không cần dựa vào thư viện để thực hiện công việc nặng nhọc. Ví dụ: Đi qua danh sách từ đầu bắt đầu bằng phần tử 0; tìm một vị trí ngẫu nhiên mới cho nó, giả sử 6, đặt giá trị 0 vào giá trị 6 và 6 trong 0. Chuyển sang phần tử 1 và lặp lại quy trình này, và tiếp tục qua phần còn lại của danh sách

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

bạn có thể trao đổi các biến trong python như thế này:my_list[i], my_list[j] = my_list[j], my_list[i]
Karolis Ryselis

-2

Nó hoạt động tốt. Tôi đang thử nó ở đây với các chức năng như các đối tượng danh sách:

    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()

Nó in ra: foo1 foo2 foo3 foo2 foo3 foo1 (các foos ở hàng cuối cùng có một thứ tự ngẫu nhiên)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.