random.choice from set? Python

91

Ich arbeite an einem KI-Teil eines Ratespiels. Ich möchte, dass die KI einen zufälligen Buchstaben aus dieser Liste auswählt. Ich mache es als Set, damit ich Buchstaben leicht aus der Liste entfernen kann, da sie im Spiel erraten werden und daher nicht mehr verfügbar sind, um erneut erraten zu werden.

Es heißt, dass das setObjekt nicht indizierbar ist. Wie kann ich das umgehen?

import random 
aiTurn=True

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



    print (aiGuess) 
Jamyn
quelle
1
Übrigens müssen Sie set (list ('string')) nicht verwenden, um eine Reihe von Buchstaben zu erhalten, da Zeichenfolgen für sich iterierbar sind - set ('abc') macht, was Sie wollen.
Scott Ritchie
4
Für andere, die auf dieses Problem stoßen, lohnt es sich, sich diese Frage anzuschauen, wie ein satzartiges Objekt erstellt werden kann, das eine effiziente zufällige Auswahl ermöglicht. Die hier angegebenen Optionen sind alle O (N). stackoverflow.com/q/15993447/2966723
Joel

Antworten:

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

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

NPE
quelle
8
Tack on a [0]am Ende, so ist es im Grunde identisch mit random.choice(was seine Werte nicht in Form einer Liste
Nick T
29
random.sampletut tuple(population)intern, random.choice(tuple(allLetters))kann also besser sein.
Utapyngo
17
Es sollte hervorgehoben werden, dass dieser Prozess O (N) ist.
Joel
@ Joel Warum ist dieser Prozess O (N)?
ManuelSchneid3r
2
Ich denke, es ist wirklich ineffizient ... Wie Sie unter github.com/python/cpython/blob/2.7/Lib/random.py#L332-L339 sehen können, erstellt die Beispielfunktion jedes Mal, wenn Sie den obigen Aufruf ausführen, eine Liste aus dem Satz nimmt ein zufälliges Element daraus. Angenommen, Sie haben ein großes Set und möchten viele Samples erstellen. Wenn sich das Set nicht ändert, ist es besser, es in eine Liste zu konvertieren und zu verwenden random.choice. Wenn sich das Set auch während des Samplings ändert, sollten Sie wahrscheinlich überhaupt kein Set verwenden. Wenn Sie die belegten Hashes im Set und die Bucket-Größen kennen würden, wäre es einfach, eine Stichprobenfunktion zu schreiben ...
jakab922
58

Sie sollten verwenden random.choice(tuple(myset)), weil es schneller und wohl sauberer aussieht als random.sample. Ich habe folgendes geschrieben, um zu testen:

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

Aus den Zahlen geht hervor, dass dies random.sample7% länger dauert.

Scott Ritchie
quelle
2
Auf meinem Computer ist random.choice siebenmal schneller.
noɥʇʎԀʎzɐɹƆ
4
Es gibt keine Möglichkeit, direkt aus dem Set auszuwählen, ohne es in ein Tupel kopieren zu müssen.
Youda008
Ich erhalte eine Probe, die ungefähr 12% (250 ms) langsamer ist als bei einem Satz von 5000 Elementen.
Simon
Auf meinem Computer ist random.samplees langsamer als random.choiceschneller, wenn die eingestellte Größe zunimmt (der Überkreuzungspunkt liegt irgendwo zwischen der eingestellten Größe 100k-500k). Das heißt, je größer das Set, desto wahrscheinlicher ist es random.sample, dass es schneller ist.
Jakee