Tại sao random.shuffle trả về Không có?


88

Tại sao random.shufflequay lại Nonebằng Python?

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

Làm cách nào để nhận giá trị xáo trộn thay vì None?


không phải giá trị ngẫu nhiên mà là xáo trộn ngẫu nhiên của danh sách.
alvas


Câu trả lời:


158

random.shuffle()thay đổi xdanh sách tại chỗ .

Các phương thức API Python thay đổi cấu trúc tại chỗ thường trả về None, không phải cấu trúc dữ liệu đã sửa đổi.

Nếu bạn muốn tạo một danh sách mới được xáo trộn ngẫu nhiên dựa trên danh sách hiện có, trong đó danh sách hiện có được giữ theo thứ tự, bạn có thể sử dụng random.sample()với độ dài đầy đủ của đầu vào:

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

Bạn cũng có thể sử dụng sorted()với random.random()cho một khóa sắp xếp:

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

nhưng điều này yêu cầu sắp xếp (một hoạt động O (NlogN)), trong khi lấy mẫu theo độ dài đầu vào chỉ thực hiện các hoạt động O (N) (quy trình tương tự như random.shuffle()được sử dụng, hoán đổi các giá trị ngẫu nhiên từ một nhóm thu hẹp).

Bản giới thiệu:

>>> 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
Việc sử dụng một keyhàm có giá trị ngẫu nhiên có thực sự đảm bảo không? Một số thuật toán sắp xếp nhanh bị bỏ qua nếu các phép so sánh không tự nhất quán. Tôi có thể thấy điều này hoạt động theo cả hai cách, tùy thuộc vào việc triển khai (trang trí-sắp xếp-trang trí sẽ chỉ cần áp dụng keymột lần trên mỗi phần tử vì vậy sẽ được xác định rõ).
torek

2
@torek: Python sử dụng trang trí-sắp xếp-trang trí khi sắp xếp với một keytệp có thể gọi. Vì vậy, có, nó được đảm bảo vì mỗi giá trị được cung cấp khóa ngẫu nhiên của chúng chính xác một lần.
Martijn Pieters

35

Phương pháp này cũng hoạt động.

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

8

Theo tài liệu :

Xáo trộn chuỗi x tại chỗ. Đối số tùy chọn ngẫu nhiên là một hàm 0 đối số trả về một số thực ngẫu nhiên trong [0.0, 1.0); theo mặc định, đây là hàm random ().

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

6

Tại sao, thực sự?

1. Hiệu quả

shufflesửa đổi danh sách tại chỗ. Điều này là tốt, bởi vì sao chép một danh sách lớn sẽ là chi phí thuần túy nếu bạn không cần danh sách gốc nữa.

2. Phong cách Pythonic

Theo nguyên tắc "rõ ràng tốt hơn là ngầm hiểu" của phong cách pythonic , trả lại danh sách sẽ là một ý tưởng tồi, bởi vì khi đó người ta có thể nghĩ rằng đó một danh sách mới mặc dù thực tế không phải vậy.

Nhưng tôi không thích nó như thế này!

Nếu bạn làm cần một danh sách trong lành, bạn sẽ phải viết một cái gì đó như

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

đó là rõ ràng độc đáo. Nếu bạn cần thành ngữ này thường xuyên, hãy gói nó trong một hàm shuffled(xem sorted) trả về new_x.


2

Tôi đã có một khoảnh khắc tuyệt vời với khái niệm này như thế này:

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

Bởi vì trăn không) "copy-by-giá trị" theo mặc định thay vì pass-by-reference = stackoverflow.com/a/986495/610569
alvas

2

Các API Python tự thay đổi cấu trúc tại chỗ trả về Không có ở dạng đầu ra.

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

Đầu ra: [1, 2, 3, 4, 5, 6, 7, 8]

from random import shuffle
print(shuffle(list))

Đầu ra: Không có

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

Đầu ra: [7, 3, 2, 4, 5, 6, 1, 8]


0

Bạn có thể trả lại danh sách xáo trộn bằng cách sử dụng random.sample()như những người khác giải thích. Nó hoạt động bằng cách lấy mẫu k phần tử từ danh sách mà không cần thay thế . Vì vậy, nếu có các phần tử trùng lặp trong danh sách của bạn, chúng sẽ được xử lý duy nhất.

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