Como selecionar aleatoriamente um item de uma lista?

1760

Suponha que eu tenha a seguinte lista:

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

Qual é a maneira mais simples de recuperar um item aleatoriamente dessa lista?

Raio
fonte

Respostas:

2678

Usar random.choice()

import random

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

Para escolhas aleatórias seguras criptograficamente (por exemplo, para gerar uma frase secreta a partir de uma lista de palavras), usesecrets.choice()

import secrets

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

secretsé novo no Python 3.6, nas versões mais antigas do Python você pode usar a random.SystemRandomclasse:

import random

secure_random = random.SystemRandom()
print(secure_random.choice(foo))
Pēteris Caune
fonte
3
Fazer duas chamadas de random.choice(foo)retorno consecutivas tem dois resultados diferentes?
Eduardo Pignatelli
34
@EduardoPignatelli Cada opção é aleatória, portanto, ele pode retornar dois resultados diferentes, mas, dependendo da semente inicial, não é garantido. Se você quiser selecionar n elementos aleatórios distintos de uma lista lst , userandom.sample(lst, n)
Graham
6
em uma nota relacionada, Standard pseudo-random generators are not suitable for security/cryptographic purposes. ref
Xiao
184

Se você deseja selecionar aleatoriamente mais de um item de uma lista ou selecionar um item de um conjunto, recomendo o uso random.sample.

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] 

Porém, se você estiver apenas puxando um único item de uma lista, a escolha será menos desajeitada, pois o uso de amostra teria a sintaxe em random.sample(some_list, 1)[0]vez de random.choice(some_list).

Infelizmente, porém, a escolha funciona apenas para uma única saída de seqüências (como listas ou tuplas). Embora random.choice(tuple(some_set))possa ser uma opção para obter um único item de um conjunto.

EDIT: Usando segredos

Como muitos apontaram, se você precisar de amostras pseudo-aleatórias mais seguras, use o módulo 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 desejar uma linha única mais pitônica para selecionar vários itens, você pode usar a descompactação.

import random
first_random_item, second_random_item = random.sample(group_of_items, 2)
Paulo
fonte
1
O secretsmódulo BTW foi adicionado à biblioteca padrão do Python na versão 3.6 python.org/dev/peps/pep-0506
and1er
160

Se você também precisar do índice, use random.randrange

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

No Python 3.6, você pode usar o secretsmódulo, que é preferível ao randommódulo para criptografia ou segurança.

Para imprimir um elemento aleatório de uma lista:

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

Para imprimir um índice aleatório:

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

Para detalhes, consulte PEP 506 .

Chris_Rands
fonte
33

Proponho um script para remover itens coletados aleatoriamente de uma lista até que ela fique vazia:

Mantenha um sete remova o elemento selecionado aleatoriamente (com choice) até que a lista esteja vazia.

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

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

Três execuções fornecem três respostas diferentes:

>>> 
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
fonte
20
Ou você poderia apenas random.shufflea listuma vez e quer iterate-lo ou colocá-la para produzir resultados. Ou resultaria em um fluxo "selecionar aleatoriamente sem repetições" perfeitamente adequado, mas a aleatoriedade seria introduzida no início.
precisa
2
Teoricamente, você pode usar o método pop () de um conjunto para remover um elemento arbitrário de um conjunto e retorná-lo, mas provavelmente não é aleatório o suficiente.
Joubarc
14
foo = ['a', 'b', 'c', 'd', 'e']
number_of_samples = 1

No python 2:

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

No python 3:

random_items = random.choices(population=foo, k=number_of_samples)
Fardin
fonte
6
Observe que random.choicesestá com substituição enquanto random.sampleestá sem substituição.
CentAu 5/0318
1
Observe também que random.choices está disponível a partir da 3.6 e posterior, não antes!
Cyril N.
11

numpy solução: numpy.random.choice

Para esta pergunta, funciona da mesma forma que a resposta aceita ( import random; random.choice()), mas eu a adicionei porque o programador já pode ter importado numpy(como eu) e também existem algumas diferenças entre os dois métodos que podem estar relacionados ao seu caso de uso real.

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

Para reprodutibilidade, você pode fazer:

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

Para amostras de um ou mais itens , retornados como um array, passe o sizeargumento:

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

Como selecionar aleatoriamente um item de uma lista?

Suponha que eu tenha a seguinte lista:

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

Qual é a maneira mais simples de recuperar um item aleatoriamente dessa lista?

Se você quiser quase aleatoriamente , sugiro secrets.choiceda biblioteca padrão (Novo no Python 3.6.):

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

O acima é equivalente à minha recomendação anterior, usando um SystemRandomobjeto do randommódulo com o choicemétodo - disponível anteriormente no Python 2:

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

E agora:

>>> 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 você deseja uma seleção pseudo-aleatória determinística, use a choicefunção (que na verdade é um método vinculado a um Randomobjeto):

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

Parece aleatório, mas na verdade não é, o que podemos ver se o repetirmos novamente:

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

Um comentário:

Não se trata de random.choice ser verdadeiramente aleatório ou não. Se você consertar a semente, obterá resultados reproduzíveis - e é para isso que a semente é projetada. Você também pode passar uma semente para o SystemRandom.sr = random.SystemRandom(42)

Bem, sim, você pode passar um argumento "semente", mas verá que o SystemRandomobjeto simplesmente o ignora :

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

se você precisar do índice, use:

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

random.choice faz o mesmo :)

Janek Olszak
fonte
2
@tc. Na verdade, faz essencialmente o mesmo. Implementação de random.choice(self, seq)is return seq[int(self.random() * len(seq))].
Wim
2
@ wim Isso é um pouco decepcionante, mas o mais decepcionante é que também é a definição de randrange()qual significa, por exemplo, random.SystemRandom().randrange(3<<51)exibe viés significativo. Suspiro ...
tc.
6
@ kevinsa5 Por fim, é porque a float(um duplo IEEE) só pode receber um número finito de valores em [0,1). Random.random()gera sua saída da maneira tradicional: escolha um número inteiro aleatório [0, 2**53)e divida por 2**53(53 é o número de bits em um dobro). Portanto, random()retorna 2 ** 53 duplos equiprobáveis, e você pode dividir isso uniformemente em saídas N apenas se N for uma potência de 2. O viés é pequeno para N pequeno, mas veja collections.Counter(random.SystemRandom().randrange(3<<51)%6 for i in range(100000)).most_common(). (O Random.nextInt () de Java evita esse viés.)
tc.
1
@tc. Suponho que algo menos do que cerca 2**40(1099511627776) seria pequeno o suficiente para que o viés não importasse na prática? Isso realmente deve ser apontado na documentação, porque se alguém não for meticuloso, talvez não espere que surjam problemas dessa parte do código.
Evgeni Sergeev
@tc .: Na verdade, randomusa getrandbitspara obter um número adequado de bits para gerar um resultado para randranges maiores ( random.choicetambém está usando isso). Isso é verdade tanto no 2.7 quanto no 3.5. Ele usa apenas self.random() * len(seq)quando getrandbitsnão está disponível. Não está fazendo a coisa estúpida que você pensa que é.
precisa
7

Este é o código com uma variável que define o índice aleatório:

import random

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

Este é o código sem a variável:

import random

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

E este é o código da maneira mais rápida e inteligente possível:

import random

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

(python 2.7)

Liam
fonte
3

O código a seguir demonstra se você precisa produzir os mesmos itens. Você também pode especificar quantas amostras deseja extrair.
O samplemétodo retorna uma nova lista contendo elementos da população, mantendo inalterada a população original. A lista resultante está na ordem de seleção, para que todas as sub-fatias também sejam amostras aleatórias válidas.

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
fonte
1

Seleção aleatória de itens:

import random

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

new_list = random.sample(my_list, num_selections)

Para preservar a ordem da lista, você pode:

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

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

Salomon Vimal
fonte
0

Também podemos fazer isso 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)
Abdul Majeed
fonte
19
Por que diabos você faria dessa maneira, quando há random.choice()e random.randrange()?
19416 alexis
"random.choice ()" fornecerá "IndexError: list index out of range" na lista vazia.
Abdul Majeed 5/09
6
Como deveria: é para isso que servem as exceções. Escolher de uma lista vazia é um erro. Retornar Noneapenas chuta a lata para algum ponto posterior aleatório, onde o "elemento" inválido dispara uma exceção; ou pior ainda, você obtém um programa incorreto em vez de uma exceção e nem o conhece.
Alexis
0

Você poderia apenas:

from random import randint

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

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