elección aleatoria del conjunto? pitón

94

Estoy trabajando en una parte de IA de un juego de adivinanzas. Quiero que la IA seleccione una letra aleatoria de esta lista. Lo hago como un conjunto para poder eliminar fácilmente las letras de la lista, ya que se adivinan en el juego y, por lo tanto, ya no están disponibles para adivinarlas nuevamente.

dice que el setobjeto no es indexable. ¿Cómo puedo solucionar esto?

import random 
aiTurn=True

while aiTurn == True:
    allLetters = set(list('abcdefghijklmnopqrstuvwxyz'))
    aiGuess=random.choice(allLetters)



    print (aiGuess) 
Jamyn
fuente
1
Por cierto, no es necesario usar set (list ('cadena')) para obtener un conjunto de letras, ya que las cadenas son iterables por sí mismas: set ('abc') hará lo que desee.
Scott Ritchie
5
Para otros que se encuentren con este problema, vale la pena mirar esta pregunta sobre cómo crear un objeto similar a un conjunto que permita una selección aleatoria eficiente. Las opciones dadas aquí son todas O (N). stackoverflow.com/q/15993447/2966723
Joel

Respuestas:

92
>>> random.sample(set('abcdefghijklmnopqrstuvwxyz'), 1)
['f']

Documentación: https://docs.python.org/3/library/random.html#random.sample

NPE
fuente
9
Agregue un [0]al final para que sea básicamente idéntico a random.choice(que no devuelve sus valores en forma de lista)
Nick T
31
random.samplelo hace tuple(population)internamente, por lo que random.choice(tuple(allLetters))puede ser mejor.
utapyngo
21
Cabe destacar que este proceso es O (N).
Joel
@Joel ¿Por qué este proceso es O (N)?
ManuelSchneid3r
2
Creo que es realmente ineficiente ... Como puede ver github.com/python/cpython/blob/2.7/Lib/random.py#L332-L339, la función de muestra crea una lista del conjunto cada vez que realiza la llamada anterior y toma un elemento aleatorio de él. Suponga que tiene un conjunto grande y desea hacer muchas muestras. Si el conjunto no cambia, es mejor convertirlo en una lista y usar random.choice. Si el conjunto también cambia mientras lo muestrea, probablemente no debería utilizar ningún conjunto. Si supiera los hashes ocupados en el conjunto y los tamaños de cubeta, sería fácil escribir una función de muestreo ...
jakab922
58

Debería usarlo random.choice(tuple(myset)), porque es más rápido y posiblemente más limpio que random.sample. Escribí lo siguiente para probar:

import random
import timeit

bigset = set(random.uniform(0,10000) for x in range(10000))

def choose():
    random.choice(tuple(bigset))

def sample():
    random.sample(bigset,1)[0]

print("random.choice:", timeit.timeit(choose, setup="global bigset", number=10000)) # 1.1082136780023575
print("random.sample:", timeit.timeit(sample, setup="global bigset", number=10000)) # 1.1889629259821959

Según los números, parece que random.sampletarda un 7% más.

Scott Ritchie
fuente
2
En mi máquina, random.choice es 7 veces más rápido.
noɥʇʎԀʎzɐɹƆ
4
¿No hay forma de seleccionar directamente desde el conjunto sin tener que copiarlo en una tupla?
Youda008
Obtengo una muestra que es aproximadamente un 12% (250 ms) más lenta que elegir en un conjunto de 5000 elementos.
Simon
1
En mi máquina, random.samplepasa de ser más lento random.choicea ser más rápido a medida que aumenta el tamaño del conjunto (el punto de cruce está en algún lugar entre el tamaño del conjunto 100k-500k). Es decir, cuanto mayor sea el conjunto, es más probable que random.samplesea ​​más rápido.
jakee