Przetasowanie listy obiektów


770

Mam listę obiektów i chcę je przetasować. Myślałem, że mogę użyć tej random.shufflemetody, ale wydaje się, że zawodzi, gdy lista obiektów. Czy istnieje metoda tasowania obiektów lub w inny sposób?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

To się nie powiedzie.


6
Czy możesz podać przykład, jak się nie udaje? random.shuffle powinien działać niezmiennie w zależności od typu obiektów na liście.
— bayer

3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. instancja w 0xb7df9e6c>, <__ main __. instancja w 0xb7df9e2c>]> >> drukuj losowo. losowo (b) Brak
— utdiscant

135
Jak podano poniżej, random.shuffle nie zwraca nowej listy losowej; tasuje listę w miejscu. Dlatego nie powinieneś mówić „drukuj losowo. Losowo (b)”, a zamiast tego wykonaj losowanie w jednym wierszu i drukuj b w następnym wierszu.
— Eli Courtwright,

Jeśli próbujesz tasować tablice numpy, zobacz moją odpowiedź poniżej.
— Gordon Bean

1
czy istnieje opcja, która nie powoduje mutacji oryginalnej tablicy, ale zwraca nową przetasowaną tablicę?
— Charlie Parker

Odpowiedzi:


1241

random.shufflepowinno działać. Oto przykład, w którym obiektami są listy:

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

Pamiętaj, że losowanie działa w miejscu i zwraca Brak.


1
@seokhoonlee Ani. Jest to generator liczb losowych pseduo, który, jeśli to możliwe, jest zasilany przez źródło prawdziwej losowości z systemu operacyjnego. Do celów innych niż kryptografia jest losowa „wystarczająca”. Jest to szczegółowo opisane w randomdokumentacji modułu .
— dimo414

2
użyj klonowania, aby uzyskać nową listę
— Mohammad Mahdi KouchakYazdi

8
czy istnieje opcja, która nie powoduje mutacji oryginalnej tablicy, ale zwraca nową przetasowaną tablicę?
— Charlie Parker

5
@CharlieParker: Nie o tym wiem. Możesz użyć random.sample(x, len(x))lub po prostu zrobić kopię i shuffleto. Dla list.sortktórych występuje podobny problem, jest teraz list.sorted, ale nie ma podobnego wariantu shuffle.
— tom10

6
@seokhonlee dla krypto-bezpiecznej losowości, użyj from random import SystemRandomzamiast tego; dodaj cryptorand = SystemRandom()i zmień wiersz 3 nacryptorand.shuffle(x)
— Browly

115

Jak się dowiedziałeś, problemem było tasowanie w miejscu. Często też mam problem i często zapominam, jak również skopiować listę. Zastosowanie sample(a, len(a))to rozwiązanie, użycie len(a)jako wielkości próbki. Zobacz https://docs.python.org/3.6/library/random.html#random.sample celu uzyskania dokumentacji Pythona.

Oto prosta wersja, random.sample()która zwraca losowy wynik jako nową listę.

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

czy istnieje opcja, która nie powoduje mutacji oryginalnej tablicy, ale zwraca nową przetasowaną tablicę?
— Charlie Parker

po prostu skopiuj listę @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(zamień; na nowe linie)
— fjsj

old[:]może również zrobić płytką kopię listy old.
— Xiao

sample()jest szczególnie pomocny przy tworzeniu prototypów analizy danych. sample(data, 2)do ustawienia kodu kleju rurociągu, a następnie „poszerzenia” go krok po kroku, do len(data).
— Katrin Leinweber,

58

Zajęło mi to również trochę czasu. Ale dokumentacja losowania jest bardzo przejrzysta:

lista losowa x na miejscu ; zwrot Brak.

Więc nie powinieneś print(random.shuffle(b)). Zamiast tego zrób random.shuffle(b)i wtedy 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

Jeśli zdarzyło Ci się już używać Numpy (bardzo popularny w zastosowaniach naukowych i finansowych), możesz zaoszczędzić sobie importu.

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

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


W tej odpowiedzi podoba mi się to, że mogę kontrolować losowe ziarno za pomocą numpy. Założę się, że jest sposób na zrobienie tego w module losowym, ale nie jest to dla mnie teraz oczywiste ... co oznacza, że ​​muszę przeczytać więcej.
— VanBantam

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

Działa dla mnie dobrze. Pamiętaj, aby ustawić metodę losową.


Nadal nie działa dla mnie, zobacz mój przykładowy kod w edytowanym pytaniu.
— utdiscant,

4
Drugi parametr ma domyślną wartość random.random. Można to całkowicie pominąć.
— cbare

3
@alvas random.shuffle (a) nic nie zwraca, tzn. zwraca None. Musisz więc sprawdzić wartość nie zwracaną.
— sonus21

15

Jeśli masz wiele list, możesz najpierw zdefiniować permutację (sposób tasowania listy / zmiany kolejności elementów na liście), a następnie zastosować ją do wszystkich list:

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

Jeśli twoje listy są tablicami liczbowymi, jest to prostsze:

import numpy as np

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

MPU

Stworzyłem mały pakiet narzędziowy, mpuktóry ma consistent_shufflefunkcję:

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)

Zauważ, że mpu.consistent_shufflepobiera dowolną liczbę argumentów. Możesz więc przetasować z nim co najmniej trzy listy.


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

Ta alternatywa może być przydatna w niektórych aplikacjach, w których chcesz zamienić funkcję zamawiania.


Zauważ też, że dzięki sortedtemu jest to funkcjonalne tasowanie (jeśli lubisz takie rzeczy).
— Inaimathi

1
To naprawdę nie rozkłada losowo wartości ze względu na stabilność Timsort. (Wartości z tym samym kluczem są pozostawione w oryginalnej kolejności.) EDYCJA: Przypuszczam, że to nie ma znaczenia, ponieważ ryzyko kolizji z 64-bitowymi zmiennoprzecinkowymi jest dość minimalne.
— Mateen Ulhaq

10

W niektórych przypadkach przy użyciu tablic numpy, przy użyciu random.shuffleutworzonych duplikatów danych w tablicy.

Alternatywą jest użycie numpy.random.shuffle. Jeśli już pracujesz z Numpy, jest to metoda preferowana w stosunku do ogólnej random.shuffle.

numpy.random.shuffle

Przykład

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

Używanie 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]])

Używanie 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
Ponadto, numpy.random.permutationmogą być interesujące: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
— Gordon Bean

Czy masz przykład tworzenia zduplikowanych danych w tablicy podczas korzystania z random.shuffle?
— nurettin

Tak - jest to uwzględnione w mojej odpowiedzi. Zobacz sekcję „Przykład”. ;)
— Gordon Bean

Nieważne, widziałem trzy elementy i pomyślałem, że to samo. Niezłe znalezisko
— nurettin

1
random.shuffleDokumentacja powinna krzyczeć Nie używać z NumPy tablic
— winterlight

10

W przypadku jedno-liniowych użyj random.sample(list_to_be_shuffled, length_of_the_list)na przykład:

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

wyjścia: [2, 9, 7, 8, 3, 0, 4, 1, 6, 5]


6

„print func (foo)” wydrukuje zwracaną wartość „func”, gdy zostanie wywołany z „foo”. „shuffle” ma jednak None jako typ zwracany, ponieważ lista zostanie zmodyfikowana w miejscu, dlatego nic nie drukuje. Obejście:

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

# print it
print(b)

Jeśli bardziej interesujesz się funkcjonalnym stylem programowania, możesz zastosować następującą funkcję otoki:

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

2
Ponieważ przekazuje odwołanie do listy, oryginał zostaje zmodyfikowany. Możesz skopiować listę przed tasowaniem za pomocą deepcopy
— shivram.ss

@ shivram.ss W tym przypadku chciałbyś czegoś takiego, random.sample(ls, len(ls))jeśli naprawdę chcesz zejść tą drogą.
— Arda Xi

4

Można zdefiniować funkcję o nazwie shuffled(w tym samym sensie 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 jest na miejscu, więc nie drukuj wyniku, który jest None, ale listę.


1

Możesz to zrobić:

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

jeśli chcesz wrócić do dwóch list, podziel tę długą listę na dwie.


1

możesz zbudować funkcję, która pobiera listę jako parametr i zwraca losową wersję listy:

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

małe wprowadzenie lub wyjaśnienie byłoby pomocne?
— kacase

funkcja jest pomocna przy tasowaniu aktywności, wyobraź sobie, że musisz potasować listę liczb trzy razy, a trzy razy potrzebujesz losowego losowania, a następnie po prostu ustaw losowy argument na True, jeśli nie potrzebujesz losowości i chcesz zachowaj tę samą kolejność tasowania, a następnie nie wprowadzaj żadnych zmian, po prostu uruchom kod.
— Josh Anish

Ponieważ nie ma przypadku użycia, w którym osoba wywołująca tę funkcję zdecydowałaby w czasie wykonywania, czy chce losowego czy losowego losowania, funkcję tę należy podzielić na dwie części.
— toolforger

Nie ma opisu, co miałoby zrobić losowe odtwarzanie losowe. (Na stycznej nie jest to odpowiedź, więc pytanie, więc nie służy celowi przepełnienia stosu).
— toolforger

1

możesz użyć losowania lub próbki. oba pochodzą z losowego modułu.

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

LUB

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

0

Upewnij się, że nie nazywasz pliku źródłowego random.py i że w katalogu roboczym nie ma pliku o nazwie random.pyc .. albo może spowodować, że Twój program spróbuje zaimportować lokalny plik random.py zamiast losowego modułu pytonów .


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

Ta funkcja może ci pomóc, jeśli nie chcesz używać losowego modułu
— Pogramist

To rozwiązanie jest nie tylko pełne, ale nieefektywne (środowisko wykonawcze jest proporcjonalne do kwadratu wielkości listy).
— toolforger

Drugą pętlę można zastąpić _list.extend(list2), która jest bardziej zwięzła ORAZ bardziej wydajna.
— toolforger

Funkcja Python, która modyfikuje parametr, nigdy nie powinna zwracać wyniku. To tylko konwencja, ale pożyteczna: ludzie często nie mają czasu, aby spojrzeć na implementację wszystkich wywoływanych funkcji, więc każdy, kto zobaczy nazwę Twojej funkcji i jej wynik, będzie bardzo zaskoczony, widząc tę ​​funkcję zaktualizuj jego parametr.
— toolforger

0
import random
class a:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1.foo,a2.foo]
random.shuffle(b)

-1

Proces tasowania odbywa się „z wymianą” , więc występowanie każdego elementu może ulec zmianie! Przynajmniej wtedy, gdy pozycje na liście również są na liście.

Na przykład,

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

Po,

random.shuffle(ml)

Liczba [0] może wynosić 9 lub 8, ale nie dokładnie 10.


-1

Plan: wypisz losowanie bez polegania na bibliotece, aby wykonać ciężkie podnoszenie. Przykład: Przejrzyj listę od początku, zaczynając od elementu 0; znajdź dla niego nową losową pozycję, powiedzmy 6, umieść wartość 0 w 6, a wartość 6 w 0. Przejdź do elementu 1 i powtórz ten proces, i tak dalej przez resztę listy

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

możesz zamieniać zmienne w pythonie w następujący sposób:my_list[i], my_list[j] = my_list[j], my_list[i]
— Karolis Ryselis

-2

To działa dobrze. Próbuję go tutaj z funkcjami jako obiektami listy:

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

Drukuje: foo1 foo2 foo3 foo2 foo3 foo1 (foos w ostatnim rzędzie mają losową kolejność)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.