Barajar una lista de objetos

771

Tengo una lista de objetos y quiero barajarlos. Pensé que podría usar el random.shufflemétodo, pero esto parece fallar cuando la lista es de objetos. ¿Hay algún método para barajar objetos u otra forma de evitar esto?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

Esto fallará.

utdiscant
fuente
66
¿Puedes dar un ejemplo de cómo falla? random.shuffle debería funcionar invariablemente para el tipo de objetos en la lista.
bayer
3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. una instancia en 0xb7df9e6c>, <__ main __. una instancia en 0xb7df9e2c>]> >> print random.shuffle (b) Ninguno
utdiscant
135
Como se indica a continuación, random.shuffle no devuelve una nueva lista aleatoria; baraja la lista en su lugar. Por lo tanto, no debe decir "print random.shuffle (b)" y, en su lugar, debe hacer la combinación aleatoria en una línea e imprimir b en la línea siguiente.
Eli Courtwright
Si está intentando mezclar matrices numpy, vea mi respuesta a continuación.
Gordon Bean
1
¿hay una opción que no mute la matriz original pero devuelva una nueva matriz aleatoria?
Charlie Parker el

Respuestas:

1241

random.shuffleDeberia trabajar. Aquí hay un ejemplo, donde los objetos son listas:

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

Tenga en cuenta que shuffle funciona en su lugar y devuelve None.

tom10
fuente
1
@seokhoonlee Ninguno de los dos. Es un generador de números pseduo-aleatorio que, cuando es posible, es sembrado por una fuente de aleatoriedad real del sistema operativo. Para todos los propósitos, excepto para la criptografía, es aleatorio "suficiente". Esto se detalla en la randomdocumentación del módulo .
dimo414
2
use clon para una nueva lista
Mohammad Mahdi KouchakYazdi
8
¿hay una opción que no mute la matriz original pero devuelva una nueva matriz aleatoria?
Charlie Parker el
55
@CharlieParker: No que yo sepa. Podrías usar random.sample(x, len(x))o simplemente hacer una copia y shuffleeso. Para lo list.sortcual tiene un problema similar, ahora hay list.sorted, pero no hay una variante similar para shuffle.
tom10
66
@seokhonlee para aleatoriedad cripto-segura, use from random import SystemRandomen su lugar; agregue cryptorand = SystemRandom()y cambie la fila 3 acryptorand.shuffle(x)
marrón
115

Como aprendiste, el problema era el barajar en el lugar. También tengo problemas con frecuencia y, a menudo, parece olvidar también cómo copiar una lista. Usar sample(a, len(a))es la solución, usar len(a)como tamaño de muestra. Consulte https://docs.python.org/3.6/library/random.html#random.sample para la documentación de Python.

Aquí hay una versión simple usando random.sample()que devuelve el resultado barajado como una nueva lista.

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
fuente
¿hay una opción que no mute la matriz original pero devuelva una nueva matriz aleatoria?
Charlie Parker el
simplemente copie la lista @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(reemplace; con nuevas líneas)
fjsj
old[:]También podría hacer una copia superficial para la lista old.
Xiao
sample()es particularmente útil para crear prototipos en un análisis de datos. sample(data, 2)para configurar el código de pegamento de una tubería, luego "ensancharlo" paso a paso, hasta len(data).
Katrin Leinweber
58

Me tomó un tiempo entender eso también. Pero la documentación para barajar es muy clara:

baraja la lista x en su lugar ; No devolver ninguno.

Entonces no deberías print(random.shuffle(b)). En cambio, hazlo random.shuffle(b)y luego print(b).

Ohad Cohen
fuente
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]
Miguel
fuente
31

Si ya estás usando numpy (muy popular para aplicaciones científicas y financieras), puedes ahorrarte una importación.

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

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

fantabolous
fuente
Lo que me gusta de esta respuesta es que puedo controlar la semilla aleatoria en numpy. Apuesto a que hay una manera de hacerlo en el módulo aleatorio, pero eso no es obvio para mí en este momento ... lo que significa que necesito leer más.
VanBantam
25
>>> import random
>>> a = ['hi','world','cat','dog']
>>> random.shuffle(a,random.random)
>>> a
['hi', 'cat', 'dog', 'world']

Funciona bien para mí. Asegúrese de establecer el método aleatorio.

Dan Lorenc
fuente
Todavía no funciona para mí, vea mi código de ejemplo en la pregunta editada.
utdiscant
44
El segundo parámetro predeterminado es random.random. Es perfectamente seguro dejarlo fuera.
cbare
3
@alvas random.shuffle (a) no devuelve nada, es decir, devuelve Ninguno. Por lo tanto, debe verificar un valor no devuelto.
sonus21
15

Si tiene varias listas, es posible que desee definir primero la permutación (la forma de barajar la lista / reorganizar los elementos de la lista) y luego aplicarla a todas las listas:

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

Si sus listas son matrices numpy, es más simple:

import numpy as np

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

mpu

He creado el pequeño paquete de utilidad mpuque tiene la consistent_shufflefunción:

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)

Tenga en cuenta que mpu.consistent_shuffletoma un número arbitrario de argumentos. Por lo tanto, también puede barajar tres o más listas con él.

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

Esta alternativa puede ser útil para algunas aplicaciones en las que desea intercambiar la función de pedido.

Jeff
fuente
Además, tenga en cuenta que, gracias a sorted, esta es una combinación funcional (si le gusta ese tipo de cosas).
Inaimathi
1
Esto realmente no distribuye aleatoriamente los valores debido a la estabilidad de Timsort. (Los valores con la misma clave se dejan en su orden original). EDITAR: Supongo que no importa, ya que el riesgo de colisión con flotadores de 64 bits es bastante mínimo.
Mateen Ulhaq
10

En algunos casos, cuando se usan matrices numpy, se usan random.shuffledatos duplicados creados en la matriz.

Una alternativa es usar numpy.random.shuffle. Si ya está trabajando con numpy, este es el método preferido sobre el genérico random.shuffle.

numpy.random.shuffle

Ejemplo

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

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

Utilizando 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]])
Frijol gordon
fuente
1
Además, numpy.random.permutationpuede ser de interés: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Gordon Bean
¿Tiene un ejemplo de datos duplicados que se crean en una matriz cuando usa random.shuffle?
nurettin
Sí, está incluido en mi respuesta. Consulte la sección titulada "Ejemplo". ;)
Gordon Bean el
No importa, vi tres elementos y pensé que era lo mismo. Bonito hallazgo
nurettin
1
random.shufflela documentación debe gritar No utilizar con matrices numpy
winterlight
10

Para líneas simples, use random.sample(list_to_be_shuffled, length_of_the_list)con un ejemplo:

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

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

weiyixie
fuente
6

'print func (foo)' imprimirá el valor de retorno de 'func' cuando se llame con 'foo'. 'shuffle' sin embargo tiene None como su tipo de retorno, ya que la lista se modificará en su lugar, por lo tanto, no imprime nada. Solución alterna:

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

# print it
print(b)

Si le gusta más el estilo de programación funcional, es posible que desee realizar la siguiente función de contenedor:

def myshuffle(ls):
    random.shuffle(ls)
    return ls
JonDoe
fuente
2
Como esto pasa una referencia a la lista, el original se modifica. Es posible que desee copiar la lista antes de barajar usando la copia profunda
shivram.ss
@ shivram.ss En este caso, querrías algo como random.sample(ls, len(ls))si realmente quisieras seguir esa ruta.
Arda Xi
4

Se puede definir una función llamada shuffled(en el mismo sentido de sortvs sorted)

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

x = shuffled([1, 2, 3, 4])
print x
malbarbo
fuente
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 está en su lugar, así que no imprima el resultado, que es None, sino la lista.

ravi tanwar
fuente
1

Puedes ir por esto:

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

si desea volver a dos listas, luego divida esta larga lista en dos.

Kiriloff
fuente
1

podría crear una función que tome una lista como parámetro y devuelva una versión aleatoria de la lista:

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
usuario8327014
fuente
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
fuente
¿Sería útil una pequeña introducción o explicación?
kacase
la función es útil para la actividad de barajar, imagina que tienes que barajar una lista de números tres veces y en las tres veces que requieras barajar aleatoriamente, luego cambia el argumento aleatorio a Verdadero si no necesitas aleatoriedad y quieres mismo orden aleatorio que se debe preservar, luego no realice ningún cambio, solo ejecute el código.
Josh Anish
Como no existe un caso de uso en el que el llamador de esta función decida en el tiempo de ejecución si desea la combinación aleatoria o no aleatoria, esta función debe dividirse en dos.
Toolforger
No hay una descripción de lo que se supone que debe hacer el shuffle no aleatorio. (En una tangente, no es una respuesta, así que la pregunta, por lo que no sirve para el desbordamiento de pila.)
toolforger
1

puedes usar shuffle o sample. los cuales provienen de un módulo aleatorio.

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
ravi tanwar
fuente
0

Asegúrese de no nombrar su archivo fuente random.py, y de que no haya un archivo en su directorio de trabajo llamado random.pyc .. cualquiera de los dos podría hacer que su programa intente importar su archivo random.py local en lugar del módulo aleatorio pythons .

user3298224
fuente
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
fuente
Esta función puede ayudarlo si no desea utilizar un módulo aleatorio
Pogramist
Esta solución no solo es detallada sino ineficiente (el tiempo de ejecución es proporcional al cuadrado del tamaño de la lista).
Toolforger
El segundo bucle podría ser reemplazado por _list.extend(list2), que es más sucinto y más eficiente.
Toolforger
Una función de Python que modifica un parámetro nunca debería devolver un resultado. Es solo una convención, pero útil: las personas a menudo carecen del tiempo para mirar la implementación de todas las funciones que llaman, por lo que cualquiera que solo vea el nombre de su función y que tenga un resultado se sorprenderá mucho al ver la función. actualizar su parámetro
toolforger
0
import random
class a:
    foo = "bar"

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

El proceso de barajado es "con reemplazo" , por lo que la aparición de cada elemento puede cambiar. Al menos cuando los elementos de tu lista también están en la lista.

P.ej,

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

Después,

random.shuffle(ml)

El número de [0] puede ser 9 u 8, pero no exactamente 10.

Gatsby
fuente
-1

Plan: escriba la barajadura sin depender de una biblioteca para hacer el trabajo pesado. Ejemplo: revise la lista desde el principio comenzando con el elemento 0; encuentre una nueva posición aleatoria para él, digamos 6, ponga el valor de 0 en 6 y el valor de 6 en 0. Pase al elemento 1 y repita este proceso, y así sucesivamente en el resto de la lista

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
fuente
Puede intercambiar variables en Python de esta manera:my_list[i], my_list[j] = my_list[j], my_list[i]
Karolis Ryselis
-2

Funciona bien. Lo estoy intentando aquí con funciones como objetos de lista:

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

Imprime: foo1 foo2 foo3 foo2 foo3 foo1 (los foos en la última fila tienen un orden aleatorio)

Stefan Gruenwald
fuente