I’m working on an AI portion of a guessing game. I want the AI to select a random letter from this list. I’m doing it as a set so I can easily remove letters from the list as they are guessed in the game and are therefore no longer available to be guessed again.
set object isn’t indexable. How can I work around this?
import random aiTurn=True while aiTurn == True: allLetters = set(list('abcdefghijklmnopqrstuvwxyz')) aiGuess=random.choice(allLetters) print (aiGuess)
Note (Oct. 2020): as of v3.9, Python has officially deprecated
random.sample() working on sets, with the official guidance being to explicitly convert the set to a list or tuple before passing it in, though this doesn’t solve the efficiency problems.
set('abcdefghijklmnopqrstuvwxyz'), 1) ['f']random.sample(
Note that choosing random elements from a set is extremely inefficient no matter how you do it – it takes time proportional to the size of the set, or worse if the set’s underlying hash table is sparse due to removed elements.
Instead, you should probably use a different data structure that supports this operation efficiently.
You should use
random.choice(tuple(myset)), because it’s faster and arguably cleaner looking than
random.sample. I wrote the following to test:
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) 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
From the numbers it seems that
random.sample takes 7% longer.
You could work around this by using a
list instead of a
set. You will still be able to remove letters “easily” from the list. Try this, for example:
allLetters = list('abcdefghijklmnopqrstuvwxyz') aiGuess = random.choice(allLetters) allLetters.remove(aiGuess)
Another option is to randomly choose the index instead of the letter, which might be slightly faster since we don’t need to search for the element to delete (but I’d question if speed actually matters here?):
allLetters = list('abcdefghijklmnopqrstuvwxyz') index = random.randint(0, len(allLetters)-1) # Top is inclusive, unlike slices aiGuess = allLetters[index] del allLetters[index]