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.

utdiscant
źródło
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.

tom10
źródło
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
Przetrząsać
źródło
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).

Ohad Cohen
źródło
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]
Michał
źródło
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

fantastyczny
źródło
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ą.

Dan Lorenc
źródło
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.

Martin Thoma
źródło
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.

Jeff
źródło
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]])
Gordon Bean
źródło
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]

weiyixie
źródło
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
JonDoe
źródło
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
malbarbo
źródło
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ę.

ravi tanwar
źródło
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.

Kiriloff
źródło
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
użytkownik8327014
źródło
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
Josh Anish
źródło
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
ravi tanwar
źródło
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 .

użytkownik3298224
źródło
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
Pogramista
źródło
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)
Xavier
źródło
-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.

Gatsby
źródło
-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
Enber
źródło
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ść)

Stefan Gruenwald
źródło