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


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.