Переміщення списку об’єктів


770

У мене є список об’єктів, і я хочу їх перемістити. Я думав, що міг би скористатися 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>]> >> надрукувати random.shuffle (b) Немає
відверто

135
Як зазначено нижче, random.shuffle не повертає новий перетасований список; вона перетасовує список на місці. Таким чином, ви не повинні говорити "print random.shuffle (b)", а натомість робити перетасування на одному рядку та друкувати b на наступному рядку.
Eli Courtwright

Якщо ви намагаєтесь перетасувати нудотні масиви, дивіться мою відповідь нижче.
Гордон Бін

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

Зауважте, що перетасування працює на місці і повертає 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)(замініть новими рядками)
fjsj

old[:]також може зробити дрібну копію для списку old.
Сяо

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

58

Мені знадобилося певний час, щоб отримати і це. Але документація на перетасування дуже чітка:

перетасувати список x на місці ; повернути Ні.

Тож не варто 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


Що мені подобається в цій відповіді, це те, що я можу контролювати випадкове насіння в рябій формі. Б'юсь об заклад, що є спосіб зробити це у випадковому модулі, але це для мене зараз очевидно ... а це означає, що мені потрібно прочитати більше.
VanBantam

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

Це прекрасно працює для мене. Обов’язково встановіть випадковий метод.


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

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цьому, це функціональне переміщення (якщо ви займаєтесь цими речами).
Inaimathi

1
Це насправді не випадково розподіляє значення через стабільність Timsort. (Значення з тим самим ключем залишаються в їх первісному порядку.) EDIT: Я вважаю, що це не має значення, оскільки ризик зіткнення з 64-бітовими плавцями зовсім мінімальний.
Матін Ульхак

10

У деяких випадках при використанні масивних масивів використовують 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?
Нуреттін

Так - це включено в мою відповідь. Дивіться розділ «Приклад». ;)
Гордон Бін

Не зважаючи, я побачив три елементи і подумав, що це те саме. Хороша знахідка
Нуреттін

1
random.shuffleДокументація повинна кричати Не використовувати з нумеровими масивами
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(у тому ж сенсі sortvs 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

невелике вступ чи пояснення було б корисним?
каказ

ця функція є корисною для перенесення переміщень, уявіть, що вам потрібно тричі переміщувати список номерів, і в три рази вам потрібно відбутися випадкове переміщення, а потім просто поверніть випадковий аргумент на Істинне інше, якщо вам не потрібна випадковість, і ви хочете той самий порядок перемішування, який потрібно зберегти, не вносити жодних змін, просто запустіть код.
Джош Аніш

Оскільки немає жодного випадку використання, коли абонент цієї функції вирішив би під час виконання, чи хоче він випадкове чи невипадкове переміщення, цю функцію слід розділити на дві частини.
toolforger

Немає опису, що передбачається робити у випадковому порядку. (У дотичній формі це не відповідь, тому питання, тому це не відповідає меті переповнення стека.)
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

Це рішення є не лише багатослівним, але й неефективним (час виконання пропорційний квадрату розміру списку).
toolforger

Другу петлю можна було замінити на _list.extend(list2), яка є більш короткою та ефективнішою.
toolforger

Функція Python, яка змінює параметр, ніколи не повинна повертати результат. Це просто умова, але корисна: людям часто не вистачає часу на перегляд виконання всіх функцій, які вони викликають, тому кожен, хто щойно бачить ім'я вашої функції, і що це має результат, буде дуже здивований, побачивши функцію оновити його параметр.
toolforger


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