Come selezionare casualmente un elemento da un elenco?


1760

Supponiamo di avere il seguente elenco:

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

Qual è il modo più semplice per recuperare un elemento a caso da questo elenco?

Risposte:


2678

Uso random.choice()

import random

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

Per scelte casuali crittograficamente sicure (ad esempio per generare una passphrase da un elenco di parole) utilizzaresecrets.choice()

import secrets

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

secretsè una novità di Python 3.6, nelle versioni precedenti di Python è possibile utilizzare la random.SystemRandomclasse:

import random

secure_random = random.SystemRandom()
print(secure_random.choice(foo))

3
Effettuare due chiamate consecutive di random.choice(foo)ritorno ha due risultati diversi?
Eduardo Pignatelli,

34
@EduardoPignatelli Ogni scelta è casuale, quindi può restituire due risultati diversi, ma a seconda del seme iniziale, non è garantito. Se si desidera selezionare n elementi casuali distinti da un elenco LST , usorandom.sample(lst, n)
Graham

6
in una nota correlata, Standard pseudo-random generators are not suitable for security/cryptographic purposes. ref
Xiao

184

Se si desidera selezionare casualmente più di un elemento da un elenco o selezionare un elemento da un set, si consiglia di utilizzare random.sampleinvece.

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] 

Se stai solo estraendo un singolo elemento da un elenco, la scelta è meno ingombrante, poiché l'utilizzo del campione avrebbe la sintassi random.sample(some_list, 1)[0]anziché random.choice(some_list).

Sfortunatamente, la scelta funziona solo per un singolo output delle sequenze (come elenchi o tuple). Sebbene random.choice(tuple(some_set))possa essere un'opzione per ottenere un singolo oggetto da un set.

EDIT: utilizzo dei segreti

Come molti hanno sottolineato, se hai bisogno di campioni pseudocasuali più sicuri, dovresti usare il modulo 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

Se si desidera un one-liner più pitone per la selezione di più elementi, è possibile utilizzare il disimballaggio.

import random
first_random_item, second_random_item = random.sample(group_of_items, 2)

1
Il secretsmodulo BTW è stato aggiunto alla libreria standard Python nella versione 3.6 python.org/dev/peps/pep-0506
e il

160

Se è necessario anche l'indice, utilizzare random.randrange

from random import randrange
random_index = randrange(len(foo))
print(foo[random_index])

42

A partire da Python 3.6 è possibile utilizzare il secretsmodulo, che è preferibile al randommodulo per scopi di crittografia o sicurezza.

Per stampare un elemento casuale da un elenco:

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

Per stampare un indice casuale:

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

Per i dettagli, vedere PEP 506 .


33

Propongo uno script per la rimozione casuale degli elementi raccolti da un elenco fino a quando non è vuoto:

Mantieni ae setrimuovi l'elemento prelevato casualmente (con choice) fino a quando l'elenco è vuoto.

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

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

Tre prove danno tre risposte diverse:

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

20
Oppure si può semplicemente random.shuffleil listtempo e sia iterare o pop per produrre risultati. O si tradurrebbe in un flusso "seleziona in modo casuale senza ripetizioni" perfettamente adeguato, è solo che la casualità verrebbe introdotta all'inizio.
ShadowRanger il

2
Teoricamente puoi usare il metodo pop () di un set per rimuovere un elemento arbitrario da un set e restituirlo, ma probabilmente non è abbastanza casuale.
Joubarc,

14
foo = ['a', 'b', 'c', 'd', 'e']
number_of_samples = 1

In Python 2:

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

In Python 3:

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

6
Si noti che random.choicesè con la sostituzione mentre random.sampleè senza sostituzione.
CentAu

1
Si noti inoltre che random.choices è disponibile dalla 3.6 e successive, non prima!
Cyril N.

11

numpy soluzione: numpy.random.choice

Per questa domanda, funziona come la risposta accettata ( import random; random.choice()), ma l'ho aggiunta perché il programmatore potrebbe aver numpygià importato (come me) e inoltre ci sono alcune differenze tra i due metodi che possono riguardare il tuo caso d'uso reale.

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

Per la riproducibilità, puoi fare:

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

Per i campioni di uno o più articoli , restituiti come an array, passare l' sizeargomento:

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

9

Come selezionare casualmente un elemento da un elenco?

Supponiamo di avere il seguente elenco:

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

Qual è il modo più semplice per recuperare un elemento a caso da questo elenco?

Se vuoi un risultato quasi casuale , suggerisco secrets.choicedalla libreria standard (Novità in Python 3.6.):

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

Quanto sopra equivale alla mia precedente raccomandazione, usando un SystemRandomoggetto dal randommodulo con il choicemetodo - disponibile in precedenza in Python 2:

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

E adesso:

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

Se si desidera una selezione pseudocasuale deterministica, utilizzare la choicefunzione (che in realtà è un metodo associato su un Randomoggetto):

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

Sembra casuale, ma in realtà non lo è, che possiamo vedere se lo abbiamo ridimensionato ripetutamente:

>>> 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 commento:

Non si tratta di stabilire se random.choice sia davvero casuale. Se aggiusti il ​​seme, otterrai risultati riproducibili - ed è per questo che è progettato il seme. Puoi anche passare un seme a SystemRandom.sr = random.SystemRandom(42)

Bene, sì, puoi passare un argomento "seed", ma vedrai che l' SystemRandomoggetto semplicemente lo ignora :

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

8

se hai bisogno dell'indice usa solo:

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

random.choice fa lo stesso :)


2
@tc. In realtà, fa essenzialmente lo stesso. L'implementazione di random.choice(self, seq)is return seq[int(self.random() * len(seq))].
mercoledì

2
@wim Questo è un po 'deludente, ma la cosa molto deludente è che è anche la definizione del randrange()che significa ad esempio che random.SystemRandom().randrange(3<<51)mostra un pregiudizio significativo. Sigh ...
tc.

6
@ kevinsa5 Alla fine è perché un float(un doppio IEEE) può prendere solo un numero finito di valori in [0,1). Random.random()genera il suo output nel modo tradizionale: scegli un numero intero casuale [0, 2**53)e dividi per 2**53(53 è il numero di bit in un doppio). Quindi random()restituisce 2 ** 53 doppi equiprobabili, e puoi dividerlo uniformemente in N output solo se N è una potenza di 2. Il bias è piccolo per N piccolo, ma vedi collections.Counter(random.SystemRandom().randrange(3<<51)%6 for i in range(100000)).most_common(). (Java's Random.nextInt () evita tale distorsione.)
tc.

1
@tc. Suppongo che qualcosa di meno di 2**40((che è 1099511627776), sarebbe abbastanza piccolo da non dare importanza al pregiudizio nella pratica? Questo dovrebbe davvero essere sottolineato nella documentazione, perché se qualcuno non è meticoloso, potrebbero non aspettarsi che i problemi provengano da questa parte del loro codice.
Evgeni Sergeev,

@tc .: In realtà, randomutilizza getrandbitsper ottenere un numero adeguato di bit per generare un risultato per randranges più grandi (lo random.choicesta anche usando). Questo vale sia per 2.7 che per 3.5. Utilizza solo self.random() * len(seq)quando getrandbitsnon è disponibile. Non sta facendo la cosa stupida che pensi che sia.
ShadowRanger il

7

Questo è il codice con una variabile che definisce l'indice casuale:

import random

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

Questo è il codice senza la variabile:

import random

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

E questo è il codice nel modo più breve e intelligente per farlo:

import random

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

(python 2.7)


3

Il seguente codice dimostra se è necessario produrre gli stessi articoli. Puoi anche specificare quanti campioni vuoi estrarre.
Il samplemetodo restituisce un nuovo elenco contenente elementi della popolazione lasciando invariata la popolazione originale. L'elenco risultante è in ordine di selezione in modo che anche tutti i sottotitoli siano campioni casuali validi.

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

1

Selezione casuale degli oggetti:

import random

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

new_list = random.sample(my_list, num_selections)

Per preservare l'ordine dell'elenco, è possibile effettuare:

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

Duplicato di https://stackoverflow.com/a/49682832/4383027


0

Possiamo anche farlo usando 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)

19
Perché mai dovresti farlo in questo modo, quando c'è random.choice()e random.randrange()?
alexis

"random.choice ()" ti darà "IndexError: elenco indice fuori intervallo" in un elenco vuoto.
Abdul Majeed,

6
Come dovrebbe: ecco a cosa servono le eccezioni. Scegliere da un elenco vuoto è un errore. Restituire Nonedà dei calci alla lattina in un punto successivo casuale in cui l '"elemento" non valido innesca un'eccezione; o peggio ancora, ottieni un programma errato invece di un'eccezione e non lo sai nemmeno.
alexis,

0

Potresti semplicemente:

from random import randint

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

print(foo[randint(0,4)])
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.