Перемешивание списка объектов


771

У меня есть список объектов, и я хочу перетасовать их. Я думал, что мог бы использовать random.shuffleметод, но это, кажется, не удается, когда список объектов. Есть ли способ перетасовки объектов или другой способ обойти это?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

Это не удастся.


6
Можете ли вы привести пример, как это не удается? random.shuffle должен работать инвариантно к типу объектов в списке.
— Байер

3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. экземпляр в 0xb7df9e6c>, <__ main __. экземпляр в 0xb7df9e2c>]> >> print random.shuffle (b) Нет
— недисциплинировано

135
Как указано ниже, random.shuffle не возвращает новый перетасованный список; это перемешивает список на месте. Так что вам не следует говорить «print random.shuffle (b)», а вместо этого делать shuffle на одной строке и печатать b на следующей.
— Эли Кортрайт

Если вы пытаетесь перетасовать пустые массивы, см. Мой ответ ниже.
— Гордон Бин

1
есть ли опция, которая не изменяет исходный массив, но возвращает новый перемешанный массив?
— Чарли Паркер

Ответы:


1241

random.shuffleдолжно сработать. Вот пример, где объекты являются списками:

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

Обратите внимание, что shuffle работает на месте и возвращает None.


1
@seokhoonlee Ни то, ни другое. Это генератор псевдослучайных чисел, который, по возможности, заполняется источником реальной случайности из ОС. Для всех целей, кроме криптографии, это случайное «достаточно». Это подробно изложено в документации randomмодуля .
— dimo414

2
использовать клон для нового списка
— Мохаммад Махди КучакЯзди

8
есть ли опция, которая не изменяет исходный массив, но возвращает новый перемешанный массив?
— Чарли Паркер

5
@CharlieParker: Не то, что я знаю. Вы можете использовать random.sample(x, len(x))или просто сделать копию и shuffleтому подобное . Для list.sortкоторого есть аналогичная проблема, есть сейчас list.sorted, но нет аналогичного варианта для shuffle.
— Tom10

6
@seokhonlee для крипто-безопасной случайности, используйте from random import SystemRandomвместо этого; добавьте cryptorand = SystemRandom()и измените строку 3 наcryptorand.shuffle(x)
— просмотрите

115

Как вы узнали, проблема была в перестановке на месте. У меня также часто бывают проблемы, и я часто забываю, как копировать список. Использование sample(a, len(a))является решением, используя len(a)в качестве размера выборки. См. Https://docs.python.org/3.6/library/random.html#random.sample для документации по Python.

Вот простая версия, использующая random.sample()возвращенный случайный результат в виде нового списка.

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

есть ли опция, которая не изменяет исходный массив, но возвращает новый перемешанный массив?
— Чарли Паркер

просто скопируйте список @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(замените; на
— новые

old[:]также может сделать мелкую копию для списка old.
— Сяо

sample()особенно полезно для прототипирования анализа данных. sample(data, 2)для настройки кода клея конвейера, а затем пошагово «расширяя» его до len(data).
— Катрин Лейнвебер

58

Мне потребовалось некоторое время, чтобы получить это тоже. Но документация по shuffle очень понятна:

Перемешать список х на месте ; вернуть нет.

Так что не стоит print(random.shuffle(b)). Вместо этого делай random.shuffle(b)и потом 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

Если вы уже используете numpy (очень популярный для научных и финансовых приложений), вы можете сэкономить импорт.

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

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


Что мне нравится в этом ответе, так это то, что я могу контролировать случайные семена в numpy. Могу поспорить, что есть способ сделать это в случайном модуле, но это не очевидно для меня прямо сейчас ... что означает, что мне нужно больше читать.
— ВанБантам

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

Он отлично работает для меня. Обязательно установите случайный метод.


Все еще не работает для меня, см. Мой пример кода в отредактированном вопросе.
— utdiscant

4
Второй параметр по умолчанию равен random.random. Совершенно безопасно оставить это.
— cbare

3
@alvas random.shuffle (a) не возвращает ничего, т. е. возвращает None. Таким образом, вы должны проверить не возвращаемое значение.
— sonus21

15

Если у вас есть несколько списков, вы можете сначала определить перестановку (способ перестановки списка / перестановки элементов в списке), а затем применить его ко всем спискам:

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

Если ваши списки являются массивами, это проще:

import numpy as np

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

MPU

Я создал небольшой пакет утилит, mpuкоторый имеет consistent_shuffleфункцию:

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)

Обратите внимание, что mpu.consistent_shuffleпринимает произвольное количество аргументов. Таким образом, вы также можете перемешать три или более списков с ним.


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

Эта альтернатива может быть полезна для некоторых приложений, где вы хотите поменять местами функцию упорядочения.


Кроме того, обратите внимание, что благодаря sortedэтому, это функциональная случайность (если вам это нравится).
— Инамати

1
Это не случайное распределение значений из-за стабильности Timsort. (Значения с одним и тем же ключом остаются в их первоначальном порядке.) РЕДАКТИРОВАТЬ: я полагаю, это не имеет значения, поскольку риск столкновения с 64-разрядными числами с плавающей запятой весьма минимален.
— Матин Улхак

10

В некоторых случаях при использовании массивов NumPy, используя random.shuffle дублированные данные в массиве.

Альтернативой является использование numpy.random.shuffle. Если вы уже работаете с numpy, это предпочтительный метод по сравнению с универсальным random.shuffle.

numpy.random.shuffle

пример

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

Использование 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]])

Использование 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
Также numpy.random.permutationмогут представлять интерес: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
— Гордон Бин

У вас есть пример создания дублированных данных в массиве при использовании random.shuffle?
— nurettin

Да, это включено в мой ответ. Смотрите раздел под названием «Пример». ;)
— Гордон Бин

Неважно, я видел три элемента и думал, что это то же самое. Хорошая находка
— nurettin

1
random.shuffleдокументация должна кричать Не используйте Numpy массивы
— winterlight

10

Для однострочников используйте random.sample(list_to_be_shuffled, length_of_the_list)пример:

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

выходы: [2, 9, 7, 8, 3, 0, 4, 1, 6, 5]


6

«print func (foo)» напечатает возвращаемое значение «func» при вызове с «foo». 'shuffle', однако, имеет None в качестве возвращаемого типа, поскольку список будет изменен на месте, следовательно, он ничего не печатает. Временное решение:

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

# print it
print(b)

Если вы больше знакомы с функциональным стилем программирования, вы можете сделать следующую функцию-обертку:

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

2
Так как это передает ссылку на список, оригинал изменяется. Возможно, вы захотите скопировать список перед перетасовкой с помощью Deepcopy
— shivram.ss

@ shivram.ss В этом случае вам нужно что-то вроде, random.sample(ls, len(ls))если вы действительно хотите пойти по этому пути.
— Арда Си

4

Можно определить функцию под названием shuffled(в том же смысле sortпротив 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 на месте, так что не печатать результат None, а список.


1

Вы можете пойти на это:

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

Если вы хотите вернуться к двум спискам, вы можете разделить этот длинный список на два.


1

Вы могли бы построить функцию, которая принимает список в качестве параметра и возвращает перемешанную версию списка:

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

небольшое введение или объяснение было бы полезно?
— Kacase

функция полезна для перетасовки действий, представьте, что вам нужно перетасовать список чисел три раза, и в трех случаях вам требуется случайное перемешивание, а затем просто поверните случайный аргумент в значение True, если вам не требуется случайность и вы хотите сохраняется тот же порядок перетасовки, затем не вносите никаких изменений, просто запустите код.
— Джош Аниш

Поскольку не существует варианта использования, когда вызывающая сторона этой функции во время выполнения решает, хочет ли он случайное или неслучайное перемешивание, эту функцию следует разделить на две части.
— инструментальный инструмент

Нет описания того, что должен делать неслучайный случайный случай. (По касательной это не ответ, поэтому вопрос, поэтому он не служит цели переполнения стека.)
— toolforger

1

Вы можете использовать случайный порядок или образец. оба из которых приходят из случайного модуля.

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

ИЛИ

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

0

Убедитесь, что вы не называете свой исходный файл random.py, и что в вашем рабочем каталоге нет файла с именем random.pyc .. либо это может привести к тому, что ваша программа попытается импортировать ваш локальный файл random.py вместо случайного модуля 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

Эта функция может помочь вам, если вы не хотите использовать случайный модуль
— Pogramist

Это решение не только многословно, но и неэффективно (время выполнения пропорционально квадрату размера списка).
— инструментальный инструмент

Второй цикл может быть заменен на _list.extend(list2), который является более кратким и более эффективным.
— инструментальный инструмент

Функция Python, которая изменяет параметр, никогда не должна возвращать результат. Это просто соглашение, но полезное: людям часто не хватает времени, чтобы посмотреть на реализацию всех функций, которые они вызывают, поэтому любой, кто просто видит имя вашей функции и имеет результат, будет очень удивлен, увидев функцию обновить его параметр.
— инструментальный инструмент


-1

Процесс перетасовки "с заменой" , поэтому появление каждого элемента может измениться! По крайней мере, когда, когда элементы в вашем списке также список.

Например,

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

После,

random.shuffle(ml)

Число [0] может быть 9 или 8, но не точно 10.


-1

План: Запишите случайное перемешивание, не полагаясь на библиотеку для выполнения тяжелой работы. Пример: просмотреть список с начала, начиная с элемента 0; найдите для него новую случайную позицию, скажем 6, поместите значение 0 в 6 и значение 6 в 0. Перейдите к элементу 1 и повторите этот процесс, и так далее до конца списка.

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

Вы можете поменять переменные в python следующим образом:my_list[i], my_list[j] = my_list[j], my_list[i]
— Karolis Ryselis

-2

Работает нормально. Я пытаюсь это здесь с функциями в качестве объектов списка:

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

Распечатывается: foo1 foo2 foo3 foo2 foo3 foo1 (foos в последнем ряду имеют случайный порядок)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.