Чому random.shuffle повертає None?


88

Чому random.shuffleповернення Noneв Python?

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

Як отримати замішане значення замість None?


не випадкове значення, а випадкове перемішування списку.
alvas


Відповіді:


157

random.shuffle()змінює xсписок на місці .

Методи API Python, які змінюють структуру на місці, зазвичай повертаються None, а не модифікована структура даних.

Якщо ви хочете створити новий довільно перетасований список на основі існуючого, де існуючий список підтримується в порядку, ви можете використовувати random.sample()з усією довжиною вводу:

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

Крім того, можна використовувати sorted()з random.random()для ключа сортування:

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

але це викликає сортування (операція O (NlogN)), тоді як вибірка на вхідну довжину займає лише операції O (N) (той самий процес, що random.shuffle()використовується, заміняючи випадкові значення зі скорочувального пулу).

Демо:

>>> 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
Чи keyсправді гарантоване використання випадкової функції? Деякі алгоритми швидкого сортування падають, якщо порівняння не узгоджуються самостійно. Я бачу, що це працює в будь-якому випадку, залежно від реалізації (decorate-sort-undecorate потрібно буде застосувати лише keyодин раз до кожного елементу, тому буде чітко визначено).
torek

2
@torek: Python використовує decoration-sort-undecorate при сортуванні за допомогою keyвиклику. Так що так, це гарантовано, оскільки кожному значенню дається випадковий ключ рівно один раз.
Мартін Пітерс


8

Відповідно до документів :

Перемішайте послідовність x на місці. Необов’язковий аргумент random - це 0-аргументна функція, що повертає випадковий плаваючий запуск у [0.0, 1.0); за замовчуванням це функція random ().

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

6

Чому, справді?

1. Ефективність

shuffleзмінює список на місці. Це приємно, тому що копіювання великого списку було б просто накладним, якщо оригінальний список вам більше не потрібен.

2. Піфонічний стиль

Відповідно до принципу "явне краще, ніж неявне" пітонічного стилю , повернення списку було б поганою ідеєю, оскільки тоді можна подумати, що це новий, хоча насправді це не так.

Але мені так не подобається!

Якщо вам дійсно потрібен свіжий список, ви повинні написати що - щось на зразок

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

що є приємним явним. Якщо вам часто потрібна ця ідіома, оберніть її у функцію shuffled(див. sorted), Яка повертається new_x.


2

У мене був ага момент з цією концепцією, як це:

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

Тому що пітон робить «копіювати-на-значення» за замовчуванням замість передачі по посиланню =) stackoverflow.com/a/986495/610569
Alvas

2

API Python, які змінюють структуру на місці, повертає None як вихід.

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

Вихід: [1, 2, 3, 4, 5, 6, 7, 8]

from random import shuffle
print(shuffle(list))

Результат: немає

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

Вихід: [7, 3, 2, 4, 5, 6, 1, 8]


0

Ви можете повернути перемішаний список, використовуючи random.sample()пояснення інших. Це працює шляхом вибірки k елементів зі списку без заміни . Тож якщо у вашому списку є повторювані елементи, вони будуть оброблятися однозначно.

>>> 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]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.