Eine Liste von Objekten mischen

770

Ich habe eine Liste von Objekten und möchte sie mischen. Ich dachte, ich könnte die random.shuffleMethode verwenden, aber dies scheint zu scheitern, wenn die Liste Objekte enthält. Gibt es eine Methode zum Mischen von Objekten oder einen anderen Weg, um dies zu umgehen?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

Dies wird fehlschlagen.

utdiscant
quelle
6
Können Sie ein Beispiel geben, wie es fehlschlägt? random.shuffle sollte unveränderlich zum Typ der Objekte in der Liste funktionieren.
Bayer
3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. eine Instanz bei 0xb7df9e6c>, <__ main __. eine Instanz bei 0xb7df9e2c>]> >> print random.shuffle (b) Keine
utdiscant
135
Wie unten angegeben, gibt random.shuffle keine neue gemischte Liste zurück. Es mischt die Liste an Ort und Stelle. Sie sollten also nicht "print random.shuffle (b)" sagen und stattdessen in einer Zeile mischen und in der nächsten Zeile b drucken.
Eli Courtwright
Wenn Sie versuchen, numpy Arrays zu mischen, lesen Sie meine Antwort unten.
Gordon Bean
1
Gibt es eine Option, die das ursprüngliche Array nicht mutiert, sondern ein neues gemischtes Array zurückgibt?
Charlie Parker

Antworten:

1241

random.shufflesollte arbeiten. Hier ist ein Beispiel, in dem die Objekte Listen sind:

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

Beachten Sie, dass Shuffle an Ort und Stelle funktioniert und None zurückgibt.

tom10
quelle
1
@seokhoonlee Weder noch. Es ist ein Pseduo-Zufallszahlengenerator, der, wenn möglich, von einer Quelle echter Zufälligkeit aus dem Betriebssystem ausgesät wird. Für alle außer Kryptographiezwecken ist es zufällig "genug". Dies ist in der randomDokumentation des Moduls ausführlich beschrieben .
dimo414
2
Verwenden Sie Klon für eine neue Liste
Mohammad Mahdi KouchakYazdi
8
Gibt es eine Option, die das ursprüngliche Array nicht mutiert, sondern ein neues gemischtes Array zurückgibt?
Charlie Parker
5
@ CharlieParker: Nicht das ich wüsste. Sie könnten random.sample(x, len(x))eine Kopie verwenden oder einfach nur erstellen shuffle. Für list.sortdie es ein ähnliches Problem gibt, gibt es jetzt list.sorted, aber es gibt keine ähnliche Variante für shuffle.
Tom10
6
@seokhonlee für kryptosichere Zufälligkeit, verwenden Sie from random import SystemRandomstattdessen; füge cryptorand = SystemRandom()Zeile 3 hinzu und ändere sie aufcryptorand.shuffle(x)
browly
115

Wie Sie erfahren haben, war das Mischen an Ort und Stelle das Problem. Ich habe auch häufig Probleme und scheine oft zu vergessen, wie man eine Liste kopiert. Verwenden sample(a, len(a))ist die Lösung, wobei len(a)als Stichprobengröße verwendet wird. Die Python-Dokumentation finden Sie unter https://docs.python.org/3.6/library/random.html#random.sample .

Hier ist eine einfache Version, random.sample()die das gemischte Ergebnis als neue Liste zurückgibt.

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
Ted
quelle
Gibt es eine Option, die das ursprüngliche Array nicht mutiert, sondern ein neues gemischtes Array zurückgibt?
Charlie Parker
Kopieren Sie einfach die Liste @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(ersetzen; durch Zeilenumbrüche)
fjsj
old[:]könnte auch eine flache Kopie für die Liste machen old.
Xiao
sample()ist besonders hilfreich für das Prototyping einer Datenanalyse. sample(data, 2)um den Klebercode einer Pipeline einzurichten und ihn dann schrittweise zu "erweitern" len(data).
Katrin Leinweber
58

Ich habe einige Zeit gebraucht, um das auch zu bekommen. Die Dokumentation für Shuffle ist jedoch sehr klar:

Shuffle Liste x anstelle ; Rückgabe Keine.

Also solltest du nicht print(random.shuffle(b)). Stattdessen random.shuffle(b)und dann print(b).

Ohad Cohen
quelle
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]
Michael
quelle
31

Wenn Sie bereits numpy verwenden (sehr beliebt für wissenschaftliche und finanzielle Anwendungen), können Sie sich einen Import sparen.

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

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

fantastisch
quelle
Was mir an dieser Antwort gefällt, ist, dass ich den zufälligen Startwert in Numpy steuern kann. Ich wette, es gibt eine Möglichkeit, dies im Zufallsmodul zu tun, aber das ist mir momentan nicht klar ... was bedeutet, dass ich mehr lesen muss.
VanBantam vor
25
>>> import random
>>> a = ['hi','world','cat','dog']
>>> random.shuffle(a,random.random)
>>> a
['hi', 'cat', 'dog', 'world']

Es funktioniert gut für mich. Stellen Sie sicher, dass Sie die Zufallsmethode festlegen.

Dan Lorenc
quelle
Funktioniert immer noch nicht für mich, siehe meinen Beispielcode in der bearbeiteten Frage.
utdiscant
4
Der zweite Parameter ist standardmäßig random.random. Es ist absolut sicher, es wegzulassen.
Cbare
3
@alvas random.shuffle (a) gibt nichts zurück, dh es gibt None zurück. Sie müssen also einen Nicht-Rückgabewert überprüfen.
Sonus21
15

Wenn Sie mehrere Listen haben, möchten Sie möglicherweise zuerst die Permutation definieren (die Art und Weise, wie Sie die Liste mischen / die Elemente in der Liste neu anordnen) und sie dann auf alle Listen anwenden:

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

Wenn Ihre Listen numpy Arrays sind, ist es einfacher:

import numpy as np

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

mpu

Ich habe das kleine Dienstprogrammpaket erstellt, mpudas die consistent_shuffleFunktion hat:

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)

Beachten Sie, dass mpu.consistent_shuffleeine beliebige Anzahl von Argumenten erforderlich ist. Sie können also auch drei oder mehr Listen damit mischen.

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

Diese Alternative kann für einige Anwendungen nützlich sein, bei denen Sie die Bestellfunktion austauschen möchten.

Jeff
quelle
Beachten Sie auch, dass dies dank sortedein funktionales Shuffle ist (wenn Sie sich für solche Dinge interessieren).
Inaimathi
1
Dies verteilt die Werte aufgrund der Stabilität von Timsort nicht wirklich zufällig. (Werte mit demselben Schlüssel bleiben in ihrer ursprünglichen Reihenfolge erhalten.) BEARBEITEN: Ich nehme an, dass dies keine Rolle spielt, da das Risiko einer Kollision mit 64-Bit-Floats recht gering ist.
Mateen Ulhaq
10

In einigen Fällen werden bei Verwendung von Numpy-Arrays random.shuffledoppelte Daten im Array erstellt.

Eine Alternative ist zu verwenden numpy.random.shuffle. Wenn Sie bereits mit numpy arbeiten, ist dies die bevorzugte Methode gegenüber der generischen random.shuffle.

numpy.random.shuffle

Beispiel

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

Verwenden von 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]])

Verwenden von 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
quelle
1
Auch numpy.random.permutationvon Interesse sein kann: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Gordon Bean
Haben Sie ein Beispiel für die Erstellung doppelter Daten in einem Array, wenn Sie random.shuffle verwenden?
Nurettin
Ja - es ist in meiner Antwort enthalten. Siehe den Abschnitt "Beispiel". ;)
Gordon Bean
Egal, ich sah drei Elemente und dachte, es sei dasselbe. Schöner Fund
Nurettin
1
random.shuffleDokumentation sollte schreien Nicht mit numpy Arrays verwenden
Winterlicht
10

Verwenden Sie für Einzeiler random.sample(list_to_be_shuffled, length_of_the_list)ein Beispiel:

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

Ausgänge: [2, 9, 7, 8, 3, 0, 4, 1, 6, 5]

weiyixie
quelle
6

'print func (foo)' gibt den Rückgabewert von 'func' aus, wenn er mit 'foo' aufgerufen wird. 'shuffle' hat jedoch None als Rückgabetyp, da die Liste an Ort und Stelle geändert wird und daher nichts gedruckt wird. Problemumgehung:

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

# print it
print(b)

Wenn Sie sich mehr für funktionalen Programmierstil interessieren, möchten Sie möglicherweise die folgende Wrapper-Funktion ausführen:

def myshuffle(ls):
    random.shuffle(ls)
    return ls
JonDoe
quelle
2
Da dies einen Verweis auf die Liste übergibt, wird das Original geändert. Sie könnten die Liste kopieren möchten , bevor Sie schlurfen deep
shivram.ss
@ shivram.ss In diesem Fall möchten Sie so etwas wie, random.sample(ls, len(ls))wenn Sie diesen Weg wirklich gehen möchten.
Arda Xi
4

Man kann eine Funktion definieren, die aufgerufen wird shuffled(im gleichen Sinne wie sortvs sorted).

def shuffled(x):
    import random
    y = x[:]
    random.shuffle(y)
    return y

x = shuffled([1, 2, 3, 4])
print x
Malbarbo
quelle
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 ist vorhanden, drucken Sie also nicht das Ergebnis None, sondern die Liste.

Ravi Tanwar
quelle
1

Sie können dies tun:

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

Wenn Sie zu zwei Listen zurückkehren möchten, teilen Sie diese lange Liste in zwei auf.

kiriloff
quelle
1

Sie können eine Funktion erstellen, die eine Liste als Parameter verwendet und eine gemischte Version der Liste zurückgibt:

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
user8327014
quelle
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
quelle
Eine kleine Einführung oder Erklärung wäre hilfreich?
Kacase
Die Funktion ist hilfreich für das Mischen von Aktivitäten. Stellen Sie sich vor, Sie müssen eine Liste von Zahlen dreimal mischen und in den drei Fällen, in denen ein zufälliges Mischen erforderlich ist, drehen Sie das zufällige Argument einfach auf True, wenn Sie keine Zufälligkeit benötigen und möchten Die gleiche Mischreihenfolge muss beibehalten werden. Nehmen Sie dann keine Änderungen vor. Führen Sie einfach den Code aus.
Josh Anish
Da es keinen Anwendungsfall gibt, in dem der Aufrufer dieser Funktion zur Laufzeit entscheiden würde, ob er das zufällige oder das nicht zufällige Mischen möchte, sollte diese Funktion in zwei Teile geteilt werden.
Werkzeugschmiede
Es gibt keine Beschreibung, was das nicht zufällige Mischen tun soll. (Auf einer Tangente ist es keine Antwort, also die Frage, also dient es nicht dem Zweck des
Stapelüberlaufs
1

Sie können entweder Shuffle oder Sample verwenden. beide stammen aus zufälligen Modulen.

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

ODER

import random
def shuffle(arr1):
    random.shuffle(arr1)
    return arr1
Ravi Tanwar
quelle
0

Stellen Sie sicher, dass Sie Ihre Quelldatei nicht random.py benennen und dass sich in Ihrem Arbeitsverzeichnis keine Datei mit dem Namen random.pyc befindet. Dies kann auch dazu führen, dass Ihr Programm versucht, Ihre lokale random.py-Datei anstelle des Python-Zufallsmoduls zu importieren .

user3298224
quelle
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
quelle
Diese Funktion kann Ihnen helfen, wenn Sie kein Zufallsmodul verwenden möchten
Pogramist
Diese Lösung ist nicht nur ausführlich, sondern auch ineffizient (die Laufzeit ist proportional zum Quadrat der Listengröße).
Werkzeugschmiede
Die zweite Schleife könnte durch ersetzt werden _list.extend(list2), was prägnanter UND effizienter ist.
Werkzeugschmiede
Eine Python-Funktion, die einen Parameter ändert, sollte niemals ein Ergebnis zurückgeben. Es ist nur eine Konvention, aber eine nützliche: Oft fehlt den Leuten die Zeit, sich mit der Implementierung aller von ihnen aufgerufenen Funktionen zu befassen. Jeder, der nur den Namen Ihrer Funktion sieht und ein Ergebnis hat, wird sehr überrascht sein, die Funktion zu sehen Aktualisieren Sie den Parameter.
Werkzeugschmiede
0
import random
class a:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1.foo,a2.foo]
random.shuffle(b)
Xavier
quelle
-1

Der Mischvorgang erfolgt "mit Ersatz" , daher kann sich das Auftreten jedes Artikels ändern! Zumindest wenn Elemente in Ihrer Liste auch Liste sind.

Z.B,

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

Nach,

random.shuffle(ml)

Die Anzahl von [0] kann 9 oder 8 sein, aber nicht genau 10.

Gatsby
quelle
-1

Plan: Schreiben Sie das Shuffle auf, ohne sich auf eine Bibliothek verlassen zu müssen, um das schwere Heben durchzuführen. Beispiel: Gehen Sie die Liste von Anfang an durch, beginnend mit Element 0; Suchen Sie eine neue zufällige Position dafür, z. B. 6, setzen Sie den Wert 0 in 6 und den Wert 6 in 0. Fahren Sie mit Element 1 fort und wiederholen Sie diesen Vorgang usw. im Rest der Liste

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
quelle
Sie können Variablen in Python wie my_list[i], my_list[j] = my_list[j], my_list[i]
folgt austauschen
-2

Es funktioniert gut. Ich versuche es hier mit Funktionen als Listenobjekte:

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

Es wird ausgedruckt: foo1 foo2 foo3 foo2 foo3 foo1 (die foos in der letzten Zeile haben eine zufällige Reihenfolge)

Stefan Gruenwald
quelle