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.

utdiscant
la source
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.

tom10
la source
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
Ted
la source
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).

Ohad Cohen
la source
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
la source
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

fantabolique
la source
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.

Dan Lorenc
la source
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.

Martin Thoma
la source
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.

Jeff
la source
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]])
Gordon Bean
la source
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]

weiyixie
la source
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
JonDoe
la source
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
malbarbo
la source
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.

ravi tanwar
la source
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.

kiriloff
la source
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
user8327014
la source
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
la source
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
ravi tanwar
la source
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. .

user3298224
la source
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
Pogrammiste
la source
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)
Xavier
la source
-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.

Gatsby
la source
-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
Enber
la source
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)

Stefan Gruenwald
la source