Почему random.shuffle
возвращается None
в Python?
>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> print shuffle(x)
None
Как мне получить перетасованное значение вместо None
?
Почему random.shuffle
возвращается None
в Python?
>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> print shuffle(x)
None
Как мне получить перетасованное значение вместо None
?
Ответы:
random.shuffle()
меняет x
список на место .
Методы Python API, которые изменяют структуру на месте, обычно возвращают None
, а не измененную структуру данных.
Если вы хотите создать новый случайным образом перетасованный список на основе существующего, где существующий список сохраняется в порядке, вы можете использовать random.sample()
с полной длиной ввода:
x = ['foo', 'bar', 'black', 'sheep']
random.sample(x, len(x))
Вы также можете использовать sorted()
with 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']
key
гарантировано использование функции со случайными значениями ? Некоторые алгоритмы быстрой сортировки не работают, если сравнения не являются самосогласованными. Я вижу, что это работает в любом случае, в зависимости от реализации (decorate-sort-undecorate нужно будет применить key
только один раз к каждому элементу, поэтому он будет четко определен).
key
вызываемого объекта. Так что да, это гарантировано, поскольку каждому значению присваивается случайный ключ ровно один раз.
Согласно документам :
Перемешайте последовательность x на место. Необязательный аргумент random - это функция с 0 аргументами, возвращающая случайное число с плавающей запятой в [0.0, 1.0); по умолчанию это функция random ().
>>> x = ['foo','bar','black','sheep']
>>> from random import shuffle
>>> shuffle(x)
>>> x
['bar', 'black', 'sheep', 'foo']
shuffle
изменяет список на месте. Это хорошо, потому что копирование большого списка было бы чистыми накладными расходами, если вам больше не нужен исходный список.
В соответствии с «явно лучше , чем неявное» принцип вещий стиля , возвращая список будет плохая идея, потому что тогда можно было бы подумать , что это новый один , хотя на самом деле это не так .
Если вам действительно нужен свежий список, вам нужно будет написать что-то вроде
new_x = list(x) # make a copy
random.shuffle(new_x)
что красиво и ясно. Если вам часто нужна эта идиома, оберните ее в функцию shuffled
(см. sorted
), Которая возвращает new_x
.
У меня был момент аха с такой концепцией:
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']
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]
Вы можете вернуть перемешанный список, используя, 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]