Mescolando un elenco di oggetti


771

Ho un elenco di oggetti e voglio mescolarli. Pensavo di poter usare il random.shufflemetodo, ma questo sembra fallire quando l'elenco è di oggetti. C'è un metodo per mescolare oggetti o un altro modo per aggirare questo?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

Questo fallirà.


6
Puoi fare un esempio di come fallisce? random.shuffle dovrebbe funzionare in modo invariante rispetto al tipo di oggetti nell'elenco.
Bayer,

3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. un'istanza a 0xb7df9e6c>, <__ main __. un'istanza a 0xb7df9e2c>]> >> print random.shuffle (b) Nessuno
utdiscant

135
Come indicato di seguito, random.shuffle non restituisce un nuovo elenco casuale; mescola l'elenco in atto. Quindi non dovresti dire "print random.shuffle (b)" e dovresti invece eseguire la riproduzione casuale su una riga e stampare b sulla riga successiva.
Eli Courtwright,

Se stai cercando di mescolare array intorpiditi, vedi la mia risposta di seguito.
Gordon Bean,

1
esiste un'opzione che non muta l'array originale ma restituisce un nuovo array mischiato?
Charlie Parker,

Risposte:


1241

random.shuffledovrebbe funzionare. Ecco un esempio, in cui gli oggetti sono elenchi:

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

Nota che shuffle funziona sul posto e restituisce None.


1
@seokhoonlee Neanche. È un generatore di numeri pseduo-casuale che, quando possibile, è seminato da una fonte di casualità reale dal sistema operativo. Per tutti tranne che per scopi di crittografia è casuale "abbastanza". Questo è dettagliato in dettaglio nella randomdocumentazione del modulo .
dimo414,

2
usa il clone per un nuovo elenco
Mohammad Mahdi KouchakYazdi

8
esiste un'opzione che non muta l'array originale ma restituisce un nuovo array mischiato?
Charlie Parker,

5
@CharlieParker: Non che io sappia. Puoi usare random.sample(x, len(x))o semplicemente fare una copia e shufflequello. Per list.sortcui ha un problema simile, ora list.sortedc'è, ma non esiste una variante simile per shuffle.
tom10

6
@seokhonlee per casualità criptata, usa from random import SystemRandominvece; aggiungi cryptorand = SystemRandom()e modifica la riga 3 acryptorand.shuffle(x)
browly

115

Come hai appreso, il problema era il mescolamento sul posto. Anch'io ho problemi di frequente e spesso sembra dimenticare anche come copiare un elenco. L'utilizzo sample(a, len(a))è la soluzione, utilizzando len(a)come dimensione del campione. Vedi https://docs.python.org/3.6/library/random.html#random.sample per la documentazione di Python.

Ecco una versione semplice usando random.sample() che che restituisce il risultato mischiato come un nuovo elenco.

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

esiste un'opzione che non muta l'array originale ma restituisce un nuovo array mischiato?
Charlie Parker,

basta copiare l'elenco @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(sostituire; con le nuove righe)
fjsj

old[:]potrebbe anche fare una copia superficiale per l'elenco old.
Xiao,

sample()è particolarmente utile per la prototipazione di un'analisi dei dati. sample(data, 2)per impostare il codice colla di una tubazione, quindi "allargarlo" per gradi, fino a len(data).
Katrin Leinweber,

58

Mi ci è voluto del tempo anche per ottenerlo. Ma la documentazione per la riproduzione casuale è molto chiara:

shuffle list x in posizione ; restituisce Nessuno.

Quindi non dovresti print(random.shuffle(b)). Invece fai random.shuffle(b)e poi 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

Se ti capita di usare già intorpidimento (molto popolare per applicazioni scientifiche e finanziarie) puoi risparmiarti un'importazione.

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

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


Quello che mi piace di questa risposta è che posso controllare il seme casuale in numpy. Scommetto che c'è un modo per farlo nel modulo casuale ma questo non è ovvio per me in questo momento ... il che significa che devo leggere di più.
VanBantam,

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

Funziona bene per me. Assicurati di impostare il metodo casuale.


Non funziona ancora per me, vedi il mio codice di esempio nella domanda modificata.
utdiscant

4
Il secondo parametro viene impostato automaticamente su random.random. È perfettamente sicuro lasciarlo fuori.
cbare,

3
@alvas random.shuffle (a) non restituisce nulla, ovvero restituisce None. Quindi devi controllare un valore non restituito.
sonus21

15

Se hai più elenchi, potresti voler definire la permutazione (il modo in cui mescoli l'elenco / riordini gli elementi nell'elenco) e poi applicalo a tutti gli elenchi:

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

Se i tuoi elenchi sono array intorpiditi, è più semplice:

import numpy as np

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

MPU

Ho creato il piccolo pacchetto di utilità mpuche ha la consistent_shufflefunzione:

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)

Si noti che mpu.consistent_shuffleaccetta un numero arbitrario di argomenti. Quindi puoi anche mescolare tre o più elenchi con esso.


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

Questa alternativa può essere utile per alcune applicazioni in cui si desidera scambiare la funzione di ordinazione.


Inoltre, tieni presente che grazie a sortedquesto è uno shuffle funzionale (se ti piace quel genere di cose).
Inaimathi,

1
Questo in realtà non distribuisce casualmente i valori a causa della stabilità di Timsort. (I valori con la stessa chiave vengono lasciati nel loro ordine originale.) MODIFICA: Suppongo che non abbia importanza poiché il rischio di collisione con float a 64 bit è piuttosto minimo.
Mateen Ulhaq,

10

In alcuni casi quando si utilizzano array intorpiditi, utilizzare random.shuffle i dati duplicati creati nell'array.

Un'alternativa è usare numpy.random.shuffle. Se stai già lavorando con numpy, questo è il metodo preferito rispetto al generico random.shuffle.

numpy.random.shuffle

Esempio

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

Utilizzando 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]])

Utilizzando 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
Inoltre, numpy.random.permutationpotrebbe essere di interesse: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Gordon Bean,

Hai un esempio di dati duplicati creati in un array quando usi random.shuffle?
Nurettin,

Sì, è incluso nella mia risposta. Vedi la sezione intitolata "Esempio". ;)
Gordon Bean,

Non importa, ho visto tre elementi e ho pensato che fosse lo stesso. Bella scoperta
nurettin

1
random.shuffledocumentazione dovrebbe gridare Non utilizzare con le matrici NumPy
Winterlight

10

Per una linea, utilizzare random.sample(list_to_be_shuffled, length_of_the_list)con un esempio:

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

uscite: [2, 9, 7, 8, 3, 0, 4, 1, 6, 5]


6

'print func (foo)' stamperà il valore di ritorno di 'func' quando viene chiamato con 'foo'. 'shuffle' ha comunque None come tipo di ritorno, poiché l'elenco verrà modificato, quindi non stampa nulla. Soluzione:

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

# print it
print(b)

Se ti piace di più lo stile di programmazione funzionale, potresti voler utilizzare la seguente funzione wrapper:

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

2
Poiché questo passa un riferimento all'elenco, l'originale viene modificato. Potresti voler copiare l'elenco prima di mescolarlo usando deepcopy
shivram.ss,

@ shivram.ss In questo caso, vorresti qualcosa come random.sample(ls, len(ls))se davvero volessi percorrere quella strada.
Arda Xi,

4

Si può definire una funzione chiamata shuffled(nello stesso senso di 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 è a posto, quindi non stampare il risultato, che è None, ma l'elenco.


1

Puoi andare per questo:

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

se vuoi tornare a due liste, allora dividi questa lunga lista in due.


1

è possibile creare una funzione che accetta un elenco come parametro e restituisce una versione casuale dell'elenco:

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

una piccola introduzione o spiegazione sarebbe utile?
kacase,

la funzione è utile per mescolare l'attività, immagina di dover mescolare un elenco di numeri per tre volte e nelle tre volte in cui è necessario che si verifichi lo shuffle casuale quindi trasforma l'argomento casuale su True else se non hai bisogno di casualità e desideri lo stesso ordine di riordino da conservare, quindi non apportare modifiche, basta eseguire il codice.
Josh Anish,

Poiché non esiste un caso d'uso in cui il chiamante di questa funzione decida in fase di esecuzione se desidera la riproduzione casuale o non casuale, questa funzione deve essere divisa in due.
Toolforger,

Non esiste una descrizione di ciò che si suppone debba fare lo shuffle non casuale. (Su una tangente, non è una risposta, quindi la domanda, quindi non serve allo scopo di Stack Overflow.)
toolforger,

1

puoi usare shuffle o sample. entrambi provengono da un modulo casuale.

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

O

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

0

Assicurati di non dare un nome al tuo file sorgente random.py e che non ci sia un file nella tua directory di lavoro chiamato random.pyc .. entrambi potrebbero causare al programma di provare a importare il tuo file random.py locale invece del modulo random di 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

Questa funzione può aiutarti se non vuoi usare il modulo casuale
Pogramist

Questa soluzione non è solo dettagliata ma inefficiente (il tempo di esecuzione è proporzionale al quadrato della dimensione dell'elenco).
Toolforger,

Il secondo ciclo potrebbe essere sostituito da _list.extend(list2), che è più conciso E più efficiente.
Toolforger,

Una funzione Python che modifica un parametro non dovrebbe mai restituire un risultato. È solo una convenzione, ma utile: le persone spesso non hanno il tempo di guardare l'implementazione di tutte le funzioni che chiamano, quindi chiunque veda solo il nome della tua funzione e che abbia un risultato sarà molto sorpreso di vederla aggiorna il suo parametro.
Toolforger,

0
import random
class a:
    foo = "bar"

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

-1

Il processo di shuffle è "con sostituzione" , quindi il verificarsi di ogni articolo può cambiare! Almeno quando anche gli elementi nell'elenco sono presenti nell'elenco.

Per esempio,

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

Dopo,

random.shuffle(ml)

Il numero di [0] può essere 9 o 8, ma non esattamente 10.


-1

Piano: Scrivi il riordino senza fare affidamento su una libreria per eseguire il sollevamento pesante. Esempio: scorrere l'elenco dall'inizio iniziando con l'elemento 0; trova una nuova posizione casuale, diciamo 6, metti il ​​valore 0 in 6 e il valore 6 in 0. Passa all'elemento 1 e ripeti questo processo, e così via per il resto dell'elenco

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

puoi scambiare le variabili in Python in questo modo:my_list[i], my_list[j] = my_list[j], my_list[i]
Karolis Ryselis il

-2

Funziona bene Lo sto provando qui con funzioni come oggetti elenco:

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

Stampa: foo1 foo2 foo3 foo2 foo3 foo1 (i foo nell'ultima riga hanno un ordine casuale)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.