random.choice dal set? pitone


94

Sto lavorando a una parte AI di un gioco di indovinelli. Voglio che l'IA selezioni una lettera a caso da questo elenco. Lo sto facendo come set in modo da poter rimuovere facilmente le lettere dall'elenco quando vengono indovinate nel gioco e quindi non sono più disponibili per essere indovinate di nuovo.

dice che l' setoggetto non è indicizzabile. Come posso aggirare questo problema?

import random 
aiTurn=True

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



    print (aiGuess) 

1
Per inciso, non è necessario utilizzare set (list ('string')) per ottenere un set di lettere poiché le stringhe sono iterabili da sole: set ('abc') farà quello che vuoi.
Scott Ritchie

5
Per gli altri che riscontrano questo problema, vale la pena esaminare questa domanda su come creare un oggetto simile a un set che consenta una selezione casuale efficiente. Le opzioni fornite qui sono tutte O (N). stackoverflow.com/q/15993447/2966723
Joel

Risposte:


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

Documentazione: https://docs.python.org/3/library/random.html#random.sample


9
Contrassegna una [0]alla fine quindi è fondamentalmente identica a random.choice(che non restituisce i suoi valori sotto forma di elenco)
Nick T

31
random.samplenon tuple(population)internamente, quindi random.choice(tuple(allLetters))può essere migliore.
utapyngo

21
Va sottolineato che questo processo è O (N).
Joel

@ Joel Perché questo processo è O (N)?
ManuelSchneid3r

2
Penso che sia davvero inefficiente ... Come puoi vedere github.com/python/cpython/blob/2.7/Lib/random.py#L332-L339 la funzione di esempio crea un elenco dal set ogni volta che effettui la chiamata sopra e prende un elemento casuale da esso. Supponi di avere un set di grandi dimensioni e di voler fare molti campioni. Se il set non cambia è meglio convertirlo in un elenco e utilizzare random.choice. Se il set cambia anche mentre lo provi, probabilmente non dovresti usare affatto un set. Se conoscessi gli hash occupati nel set e le dimensioni del bucket sarebbe facile scrivere una funzione di campionamento ...
jakab922

58

Dovresti usare random.choice(tuple(myset)), perché è più veloce e probabilmente più pulito di random.sample. Ho scritto quanto segue per testare:

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

Dai numeri sembra che random.sampleci voglia il 7% in più.


2
Sulla mia macchina, random.choice è 7 volte più veloce.
noɥʇʎԀʎzɐɹƆ

4
Non c'è modo di selezionare direttamente dal set, senza doverlo copiare nella tupla?
Youda008

Ottengo che il campione sia circa il 12% (250 ms) più lento rispetto a quello scelto su un set di 5000 elementi.
Simon

1
Sulla mia macchina, random.samplepassa dall'essere più lento all'essere più random.choiceveloce di esso man mano che la dimensione impostata cresce (il punto di crossover è da qualche parte tra la dimensione impostata 100k-500k). Cioè, più grande è il set, più è probabile che random.samplesia più veloce.
jakee
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.