Lecture aléatoire d'une liste d'objets


771

J'ai une liste d'objets et je veux les mélanger. Je pensais pouvoir utiliser la random.shuffleméthode, mais cela semble échouer lorsque la liste est constituée d'objets. Existe-t-il une méthode pour mélanger les objets ou une autre solution?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

Cela échouera.


6
Pouvez-vous donner un exemple de son échec? random.shuffle devrait fonctionner invariant au type des objets dans la liste.
bayer

3
>>> a1 = a () >>> a2 = a () >>> b = [a1, a2] >>> b [<__ main __. une instance à 0xb7df9e6c>, <__ main __. une instance à 0xb7df9e2c>]> >> print random.shuffle (b) None
utdiscant

135
Comme indiqué ci-dessous, random.shuffle ne renvoie pas de nouvelle liste mélangée; il mélange la liste en place. Vous ne devez donc pas dire "print random.shuffle (b)" et devez plutôt faire le shuffle sur une ligne et imprimer b sur la ligne suivante.
Eli Courtwright

Si vous essayez de mélanger les tableaux numpy, consultez ma réponse ci-dessous.
Gordon Bean

1
existe-t-il une option qui ne mute pas le tableau d'origine mais renvoie un nouveau tableau mélangé?
Charlie Parker

Réponses:


1241

random.shuffledevrait marcher. Voici un exemple, où les objets sont des listes:

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

Notez que la lecture aléatoire fonctionne en place et renvoie Aucun.


1
@seokhoonlee Ni l'un ni l'autre. Il s'agit d'un générateur de nombres pséduo-aléatoires qui, lorsque cela est possible, est ensemencé par une source de véritable aléa du système d'exploitation. À toutes fins, sauf à des fins de cryptographie, il est aléatoire "assez". Ceci est détaillé dans la randomdocumentation du module .
dimo414

2
utiliser un clone pour une nouvelle liste
Mohammad Mahdi KouchakYazdi

8
existe-t-il une option qui ne mute pas le tableau d'origine mais renvoie un nouveau tableau mélangé?
Charlie Parker

5
@CharlieParker: Pas que je sache. Vous pouvez utiliser random.sample(x, len(x))ou simplement faire une copie et shufflecela. Pour list.sortqui a un problème similaire, il y en a maintenant list.sorted, mais il n'y a pas de variante similaire pour shuffle.
tom10

6
@seokhonlee pour l'aléatoire crypto-sécurisé, utilisez à la from random import SystemRandomplace; ajoutez cryptorand = SystemRandom()et changez la ligne 3 encryptorand.shuffle(x)
browly

115

Comme vous l'avez appris, le brassage sur place était le problème. J'ai aussi souvent des problèmes et j'ai souvent l'impression d'oublier comment copier une liste. Utiliser sample(a, len(a))est la solution, utiliser len(a)comme taille d'échantillon. Voir https://docs.python.org/3.6/library/random.html#random.sample pour la documentation Python.

Voici une version simple utilisant random.sample()qui renvoie le résultat mélangé dans une nouvelle liste.

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

existe-t-il une option qui ne mute pas le tableau d'origine mais renvoie un nouveau tableau mélangé?
Charlie Parker

il suffit de copier la liste @CharlieParker: old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)(remplacer; avec des nouvelles lignes)
fjsj

old[:]pourrait également faire une copie peu profonde pour la liste old.
Xiao

sample()est particulièrement utile pour le prototypage d'une analyse de données. sample(data, 2)pour configurer le code de colle d'un pipeline, puis "l'élargir" par étapes, jusqu'à len(data).
Katrin Leinweber

58

Il m'a fallu un certain temps pour l'obtenir aussi. Mais la documentation de shuffle est très claire:

mélanger la liste x en place ; aucun retour.

Vous ne devriez donc pas print(random.shuffle(b)). Faites plutôt random.shuffle(b)et ensuite 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

Si vous utilisez déjà numpy (très populaire pour les applications scientifiques et financières), vous pouvez vous enregistrer une importation.

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

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


Ce que j'aime dans cette réponse, c'est que je peux contrôler la graine aléatoire dans numpy. Je parie qu'il existe un moyen de le faire dans le module aléatoire, mais cela n'est pas évident pour moi en ce moment ... ce qui signifie que j'ai besoin de lire plus.
VanBantam

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

Ça fonctionne bien pour moi. Assurez-vous de définir la méthode aléatoire.


Ne fonctionne toujours pas pour moi, voir mon exemple de code dans la question modifiée.
utdiscant

4
Le deuxième paramètre par défaut est random.random. Il est parfaitement sûr de le laisser de côté.
cbare

3
@alvas random.shuffle (a) ne renvoie rien, c'est-à-dire qu'il n'en renvoie aucun. Vous devez donc vérifier une valeur de non retour.
sonus21

15

Si vous avez plusieurs listes, vous souhaiterez peut-être d'abord définir la permutation (la façon dont vous mélangez la liste / réorganisez les éléments de la liste), puis l'appliquez à toutes les listes:

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 vos listes sont des tableaux numpy, c'est plus simple:

import numpy as np

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

mpu

J'ai créé le petit paquet utilitaire mpuqui a la consistent_shufflefonction:

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)

Notez que cela mpu.consistent_shuffleprend un nombre arbitraire d'arguments. Vous pouvez donc également mélanger trois listes ou plus avec.


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

Cette alternative peut être utile pour certaines applications où vous souhaitez échanger la fonction de commande.


Notez également que grâce à sorted, c'est un remaniement fonctionnel (si vous êtes dans ce genre de chose).
Inaimathi

1
Cela ne distribue pas vraiment au hasard les valeurs en raison de la stabilité de Timsort. (Les valeurs avec la même clé sont conservées dans leur ordre d'origine.) EDIT: Je suppose que cela n'a pas d'importance car le risque de collision avec des flottants 64 bits est assez minime.
Mateen Ulhaq

10

Dans certains cas, lors de l'utilisation de tableaux numpy, à l'aide de random.shuffledonnées en double créées dans le tableau.

Une alternative est d'utiliser numpy.random.shuffle. Si vous travaillez déjà avec numpy, c'est la méthode préférée par rapport au générique random.shuffle.

numpy.random.shuffle

Exemple

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

En utilisant 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]])

En utilisant 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
En outre, numpy.random.permutationpeuvent intéresser: stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Bean Gordon

Avez-vous un exemple de données dupliquées en cours de création dans un tableau lors de l'utilisation de random.shuffle?
nurettin

Oui, c'est inclus dans ma réponse. Voir la section intitulée "Exemple". ;)
Gordon Bean

Peu importe, j'ai vu trois éléments et j'ai pensé que c'était la même chose. Nice find
nurettin

1
random.shufflela documentation doit crier Ne pas utiliser avec les tableaux
numpy

10

Pour les monolignes, utilisez random.sample(list_to_be_shuffled, length_of_the_list)avec un exemple:

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

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


6

'print func (foo)' affichera la valeur de retour de 'func' lorsqu'il est appelé avec 'foo'. 'shuffle' a cependant None comme type de retour, car la liste sera modifiée sur place, donc elle n'imprime rien. Solution de contournement:

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

# print it
print(b)

Si vous êtes plus dans le style de programmation fonctionnel, vous voudrez peut-être faire la fonction wrapper suivante:

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

2
Comme cela transmet une référence à la liste, l'original est modifié. Vous voudrez peut-être copier la liste avant de mélanger à l'aide de deepcopy
shivram.ss

@ shivram.ss Dans ce cas, vous voudriez quelque chose comme random.sample(ls, len(ls))si vous voulez vraiment emprunter cette voie.
Arda Xi

4

On peut définir une fonction appelée shuffled(dans le même sens de 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 est en place, donc n'imprimez pas le résultat, ce qui est le cas None, mais la liste.


1

Vous pouvez y aller:

>>> 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 vous souhaitez revenir à deux listes, vous divisez ensuite cette longue liste en deux.


1

vous pouvez créer une fonction qui prend une liste en paramètre et renvoie une version mélangée de la liste:

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

une petite introduction ou explication serait utile?
kacase

la fonction est utile pour mélanger l'activité, imaginez que vous devez mélanger une liste de nombres pour trois fois et dans les trois fois vous avez besoin d'un mélange aléatoire pour se produire, puis tournez l'argument aléatoire sur True else si vous n'avez pas besoin de hasard et que vous voulez même ordre de brassage à conserver, puis ne faites aucune modification, exécutez simplement le code.
Josh Anish

Puisqu'il n'y a pas de cas d'utilisation où l'appelant de cette fonction déciderait au moment de l'exécution s'il veut le mélange aléatoire ou non aléatoire, cette fonction doit être divisée en deux.
toolforger

Il n'y a aucune description de ce que le shuffle non aléatoire est censé faire. (Sur une tangente, ce n'est pas une réponse donc la question, donc ça ne sert pas le but de Stack Overflow.)
toolforger

1

vous pouvez soit utiliser shuffle ou sample. les deux proviennent d'un module aléatoire.

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

OU

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

0

Assurez-vous que vous ne nommez pas votre fichier source random.py et qu'il n'y a pas de fichier dans votre répertoire de travail appelé random.pyc. .


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

Cette fonction peut vous aider si vous ne voulez pas utiliser de module aléatoire
Pogrammiste

Cette solution est non seulement détaillée mais inefficace (le temps d'exécution est proportionnel au carré de la taille de la liste).
toolforger

La deuxième boucle pourrait être remplacée par _list.extend(list2), qui est plus succincte et plus efficace.
toolforger

Une fonction Python qui modifie un paramètre ne doit jamais retourner de résultat. C'est juste une convention, mais utile: les gens manquent souvent de temps pour regarder la mise en œuvre de toutes les fonctions qu'ils appellent, donc toute personne qui ne verra que le nom de votre fonction et qui aura un résultat sera très surprise de voir la fonction mettre à jour son paramètre.
toolforger

0
import random
class a:
    foo = "bar"

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

-1

Le processus de mélange est "avec remplacement" , donc l'occurrence de chaque élément peut changer! Au moins lorsque les éléments de votre liste sont également listés.

Par exemple,

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

Après,

random.shuffle(ml)

Le nombre de [0] peut être 9 ou 8, mais pas exactement 10.


-1

Plan: Écrivez le mélange sans compter sur une bibliothèque pour faire le gros du travail. Exemple: Parcourez la liste depuis le début en commençant par l'élément 0; trouver une nouvelle position aléatoire pour lui, disons 6, mettre la valeur 0 dans 6 et la valeur 6 dans 0. Passez à l'élément 1 et répétez ce processus, et ainsi de suite dans le reste de la 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

vous pouvez échanger des variables en python comme ceci:my_list[i], my_list[j] = my_list[j], my_list[i]
Karolis Ryselis

-2

Ça fonctionne bien. Je l'essaye ici avec des fonctions comme objets de liste:

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

Il affiche: foo1 foo2 foo3 foo2 foo3 foo1 (les foos de la dernière ligne ont un ordre aléatoire)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.