Comment sélectionner au hasard un élément dans une liste?

1761

Supposons que j'ai la liste suivante:

foo = ['a', 'b', 'c', 'd', 'e']

Quelle est la manière la plus simple de récupérer un élément au hasard dans cette liste?

Rayon
la source

Réponses:

2680

Utilisation random.choice()

import random

foo = ['a', 'b', 'c', 'd', 'e']
print(random.choice(foo))

Pour des choix aléatoires cryptographiquement sécurisés (par exemple pour générer une phrase secrète à partir d'une liste de mots), utilisezsecrets.choice()

import secrets

foo = ['battery', 'correct', 'horse', 'staple']
print(secrets.choice(foo))

secretsest nouveau dans Python 3.6, sur les anciennes versions de Python, vous pouvez utiliser la random.SystemRandomclasse:

import random

secure_random = random.SystemRandom()
print(secure_random.choice(foo))
Pēteris Caune
la source
3
Est-ce que faire deux appels de random.choice(foo)retour consécutifs donne deux résultats différents?
Eduardo Pignatelli
34
@EduardoPignatelli Chaque choix est aléatoire, il peut donc renvoyer deux résultats différents, mais selon la graine de départ, ce n'est pas garanti. Si vous voulez sélectionner n éléments aléatoires distincts dans une liste lst , utilisezrandom.sample(lst, n)
Graham
6
sur une note connexe, Standard pseudo-random generators are not suitable for security/cryptographic purposes. ref
Xiao
184

Si vous souhaitez sélectionner au hasard plusieurs éléments dans une liste, ou sélectionner un élément dans un ensemble, je vous recommande d'utiliser à la random.sampleplace.

import random
group_of_items = {1, 2, 3, 4}               # a sequence or set will work here.
num_to_select = 2                           # set the number to select here.
list_of_random_items = random.sample(group_of_items, num_to_select)
first_random_item = list_of_random_items[0]
second_random_item = list_of_random_items[1] 

Si vous ne retirez qu'un seul élément d'une liste, le choix est moins maladroit, car l'utilisation de sample aurait la syntaxe à la random.sample(some_list, 1)[0]place de random.choice(some_list).

Malheureusement, le choix ne fonctionne que pour une seule sortie de séquences (telles que des listes ou des tuples). Bien que cela random.choice(tuple(some_set))puisse être une option pour obtenir un seul élément d'un ensemble.

EDIT: Utilisation des secrets

Comme beaucoup l'ont souligné, si vous avez besoin d'échantillons pseudo-aléatoires plus sécurisés, vous devez utiliser le module secrets:

import secrets                              # imports secure module.
secure_random = secrets.SystemRandom()      # creates a secure random object.
group_of_items = {1, 2, 3, 4}               # a sequence or set will work here.
num_to_select = 2                           # set the number to select here.
list_of_random_items = secure_random.sample(group_of_items, num_to_select)
first_random_item = list_of_random_items[0]
second_random_item = list_of_random_items[1]

EDIT: Pythonic One-Liner

Si vous voulez une doublure plus pythonique pour sélectionner plusieurs articles, vous pouvez utiliser le déballage.

import random
first_random_item, second_random_item = random.sample(group_of_items, 2)
Paul
la source
1
Le secretsmodule BTW a été ajouté à la bibliothèque standard Python dans la version 3.6 python.org/dev/peps/pep-0506
et1er
160

Si vous avez également besoin de l'index, utilisez random.randrange

from random import randrange
random_index = randrange(len(foo))
print(foo[random_index])
Juampi
la source
42

Depuis Python 3.6, vous pouvez utiliser le secretsmodule, qui est préférable au randommodule pour des utilisations de cryptographie ou de sécurité.

Pour imprimer un élément aléatoire à partir d'une liste:

import secrets
foo = ['a', 'b', 'c', 'd', 'e']
print(secrets.choice(foo))

Pour imprimer un index aléatoire:

print(secrets.randbelow(len(foo)))

Pour plus de détails, voir PEP 506 .

Chris_Rands
la source
33

Je propose un script pour supprimer les éléments ramassés au hasard d'une liste jusqu'à ce qu'elle soit vide:

Maintenez un setélément et supprimez-le au hasard (avec choice) jusqu'à ce que la liste soit vide.

s=set(range(1,6))
import random

while len(s)>0:
  s.remove(random.choice(list(s)))
  print(s)

Trois pistes donnent trois réponses différentes:

>>> 
set([1, 3, 4, 5])
set([3, 4, 5])
set([3, 4])
set([4])
set([])
>>> 
set([1, 2, 3, 5])
set([2, 3, 5])
set([2, 3])
set([2])
set([])

>>> 
set([1, 2, 3, 5])
set([1, 2, 3])
set([1, 2])
set([1])
set([])
kiriloff
la source
20
Ou vous pouvez random.shufflele faire listune seule fois et le répéter ou le faire éclater pour produire des résultats. L'une ou l'autre résulterait en un flux "sélectionner au hasard parfaitement adéquat sans répétition", c'est juste que l'aléatoire serait introduit au début.
ShadowRanger
2
Théoriquement, vous pouvez utiliser la méthode pop () d'un ensemble pour supprimer un élément arbitraire d'un ensemble et le renvoyer, mais ce n'est probablement pas assez aléatoire.
Joubarc
14
foo = ['a', 'b', 'c', 'd', 'e']
number_of_samples = 1

En python 2:

random_items = random.sample(population=foo, k=number_of_samples)

En python 3:

random_items = random.choices(population=foo, k=number_of_samples)
Fardin
la source
6
Notez que random.choicesc'est avec remplacement tandis qu'il random.sampleest sans remplacement.
CentAu
1
Notez également que random.choices est disponible à partir de 3.6 et versions ultérieures, pas avant!
Cyril N.20
11

numpy Solution: numpy.random.choice

Pour cette question, cela fonctionne de la même manière que la réponse acceptée ( import random; random.choice()), mais je l'ai ajoutée parce que le programmeur a peut-être numpydéjà importé (comme moi) et il existe également des différences entre les deux méthodes qui peuvent concerner votre cas d'utilisation réel.

import numpy as np    
np.random.choice(foo) # randomly selects a single item

Pour la reproductibilité, vous pouvez faire:

np.random.seed(123)
np.random.choice(foo) # first call will always return 'c'

Pour les échantillons d' un ou plusieurs éléments , renvoyés sous forme de array, passez l' sizeargument:

np.random.choice(foo, 5)          # sample with replacement (default)
np.random.choice(foo, 5, False)   # sample without replacement
C8H10N4O2
la source
9

Comment sélectionner au hasard un élément dans une liste?

Supposons que j'ai la liste suivante:

foo = ['a', 'b', 'c', 'd', 'e']  

Quelle est la manière la plus simple de récupérer un élément au hasard dans cette liste?

Si vous voulez près de vraiment aléatoire , alors je suggère secrets.choicede la bibliothèque standard (Nouveau dans Python 3.6.):

>>> from secrets import choice         # Python 3 only
>>> choice(list('abcde'))
'c'

Ce qui précède est équivalent à mon ancienne recommandation, en utilisant un SystemRandomobjet du randommodule avec la choiceméthode - disponible plus tôt dans Python 2:

>>> import random                      # Python 2 compatible
>>> sr = random.SystemRandom()
>>> foo = list('abcde')
>>> foo
['a', 'b', 'c', 'd', 'e']

Et maintenant:

>>> sr.choice(foo)
'd'
>>> sr.choice(foo)
'e'
>>> sr.choice(foo)
'a'
>>> sr.choice(foo)
'b'
>>> sr.choice(foo)
'a'
>>> sr.choice(foo)
'c'
>>> sr.choice(foo)
'c'

Si vous voulez une sélection pseudo-aléatoire déterministe, utilisez la choicefonction (qui est en fait une méthode liée sur un Randomobjet):

>>> random.choice
<bound method Random.choice of <random.Random object at 0x800c1034>>

Cela semble aléatoire, mais ce n'est pas le cas, ce que nous pouvons voir si nous le réensemencons à plusieurs reprises:

>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')
>>> random.seed(42); random.choice(foo), random.choice(foo), random.choice(foo)
('d', 'a', 'b')

Un commentaire:

Il ne s'agit pas de savoir si random.choice est vraiment aléatoire ou non. Si vous réparez la graine, vous obtiendrez des résultats reproductibles - et c'est pour cela que la graine est conçue. Vous pouvez également transmettre une graine à SystemRandom.sr = random.SystemRandom(42)

Eh bien, oui, vous pouvez lui passer un argument "seed", mais vous verrez que l' SystemRandomobjet l'ignore simplement :

def seed(self, *args, **kwds):
    "Stub method.  Not used for a system random number generator."
    return None
Aaron Hall
la source
8

si vous avez besoin de l'index, utilisez simplement:

import random
foo = ['a', 'b', 'c', 'd', 'e']
print int(random.random() * len(foo))
print foo[int(random.random() * len(foo))]

random.choice fait de même :)

Janek Olszak
la source
2
@tc. En fait, il fait essentiellement la même chose. La mise en œuvre de random.choice(self, seq)is return seq[int(self.random() * len(seq))].
wim
2
@wim C'est un peu décevant, mais ce qui est très décevant, c'est que c'est aussi la définition de randrange()ce qui signifie, par exemple, random.SystemRandom().randrange(3<<51)présente un biais significatif. Soupir ...
tc.
6
@ kevinsa5 En fin de compte, c'est parce qu'un float(un double IEEE) ne peut prendre qu'un nombre fini de valeurs dans [0,1). Random.random()génère sa sortie de la manière traditionnelle: choisissez un entier aléatoire [0, 2**53)et divisez par 2**53(53 est le nombre de bits dans un double). Renvoie donc random()2 ** 53 doubles équiprobables, et vous pouvez diviser cela en N sorties uniquement si N est une puissance de 2. Le biais est petit pour N petit, mais voyez collections.Counter(random.SystemRandom().randrange(3<<51)%6 for i in range(100000)).most_common(). (Java's Random.nextInt () évite un tel biais.)
tc.
1
@tc. Je suppose que quelque chose de moins qu'environ 2**40, (qui est 1099511627776), serait assez petit pour que le biais n'ait pas d'importance dans la pratique? Cela devrait vraiment être souligné dans la documentation, car si quelqu'un n'est pas méticuleux, il ne devrait pas s'attendre à ce que des problèmes viennent de cette partie de son code.
Evgeni Sergeev
@tc .: En fait, randomutilise getrandbitspour obtenir un nombre suffisant de bits pour générer un résultat pour des randranges plus grands ( random.choiceutilise également cela). Cela est vrai pour les versions 2.7 et 3.5. Il utilise uniquement self.random() * len(seq)lorsque getrandbitsn'est pas disponible. Il ne fait pas la chose stupide que vous pensez.
ShadowRanger
7

Voici le code avec une variable qui définit l'index aléatoire:

import random

foo = ['a', 'b', 'c', 'd', 'e']
randomindex = random.randint(0,len(foo)-1) 
print (foo[randomindex])
## print (randomindex)

Voici le code sans la variable:

import random

foo = ['a', 'b', 'c', 'd', 'e']
print (foo[random.randint(0,len(foo)-1)])

Et voici le code de la manière la plus courte et la plus intelligente pour le faire:

import random

foo = ['a', 'b', 'c', 'd', 'e']
print(random.choice(foo))

(python 2.7)

Liam
la source
3

Le code suivant montre si vous devez produire les mêmes éléments. Vous pouvez également spécifier le nombre d'échantillons que vous souhaitez extraire.
La sampleméthode renvoie une nouvelle liste contenant des éléments de la population tout en laissant la population d'origine inchangée. La liste résultante est dans l'ordre de sélection afin que toutes les sous-tranches soient également des échantillons aléatoires valides.

import random as random
random.seed(0)  # don't use seed function, if you want different results in each run
print(random.sample(foo,3))  # 3 is the number of sample you want to retrieve

Output:['d', 'e', 'a']
Memin
la source
1

Sélection aléatoire d'éléments:

import random

my_list = [1, 2, 3, 4, 5]
num_selections = 2

new_list = random.sample(my_list, num_selections)

Pour conserver l'ordre de la liste, vous pouvez faire:

randIndex = random.sample(range(len(my_list)), n_selections)
randIndex.sort()
new_list = [my_list[i] for i in randIndex]

Duplicata de https://stackoverflow.com/a/49682832/4383027

Salomon Vimal
la source
0

Nous pouvons également le faire en utilisant randint.

from random import randint
l= ['a','b','c']

def get_rand_element(l):
    if l:
        return l[randint(0,len(l)-1)]
    else:
        return None

get_rand_element(l)
Abdul Majeed
la source
19
Pourquoi diable le feriez-vous de cette façon, quand il y a random.choice()et random.randrange()?
alexis
"random.choice ()" vous donnera "IndexError: list index out of range" sur une liste vide.
Abdul Majeed
6
Comme il se doit: c'est à cela que servent les exceptions. Choisir dans une liste vide est une erreur. Le retour Nonene fait que donner un coup de pied à la boîte à un point ultérieur aléatoire où «l'élément» invalide déclenche une exception; ou pire encore, vous obtenez un programme incorrect au lieu d'une exception, et vous ne le savez même pas.
alexis
0

Vous pourriez simplement:

from random import randint

foo = ["a", "b", "c", "d", "e"]

print(foo[randint(0,4)])
Evan Schwartzentruber
la source