140 votes

choix aléatoire à partir d'un ensemble ? python

Je travaille sur une partie IA d'un jeu de devinettes. Je veux que l'IA choisisse une lettre au hasard dans cette liste. Je fais cela comme un ensemble afin de pouvoir facilement retirer les lettres de la liste lorsqu'elles sont devinées dans le jeu et ne sont donc plus disponibles pour être devinées à nouveau.

il dit set n'est pas indexable. Comment puis-je contourner ce problème ?

import random 
aiTurn=True

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

    print (aiGuess)

140voto

NPE Points 169956

Note (Oct. 2020) : à partir de la version 3.9, Python a officiellement déprécié random.sample() travaillant sur des ensembles, le conseil officiel étant de convertir explicitement l'ensemble en une liste ou un tuple avant de le passer, bien que cela ne résolve pas les problèmes d'efficacité.


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

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

Notez que choisir des éléments aléatoires dans un ensemble est extrêmement inefficace quelle que soit la façon dont vous le faites - cela prend un temps proportionnel à la taille de l'ensemble, ou pire si la table de hachage sous-jacente de l'ensemble est clairsemée en raison des éléments supprimés.

Au lieu de cela, vous devriez probablement utiliser un structure de données différente qui supporte efficacement cette opération.

74voto

Scott Ritchie Points 1528

Vous devez utiliser random.choice(tuple(myset)) parce qu'il est plus rapide et plus propre que l'option random.sample . J'ai écrit ce qui suit pour le tester :

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

D'après les chiffres, il semble que random.sample prend 7 % de plus.

1voto

zerozero nine Points 11

Comme la liste de choix n'est pas très longue, vous pouvez utiliser random.shuffle la liste en premier. Ensuite, vous pouvez itérer chaque élément de la liste. Cela évite de supprimer les éléments d'une liste un par un et rend votre code plus propre.

0voto

Moot Points 963

Vous pouvez contourner ce problème en utilisant un list au lieu d'un set . Vous pourrez toujours retirer les lettres "facilement" de la liste. Essayez ceci, par exemple :

allLetters = list('abcdefghijklmnopqrstuvwxyz')
aiGuess = random.choice(allLetters)
allLetters.remove(aiGuess)

Une autre option consiste à choisir aléatoirement l'indice au lieu de la lettre, ce qui pourrait être légèrement plus rapide puisque nous n'avons pas besoin de rechercher l'élément à supprimer (mais je me demande si la rapidité compte vraiment ici ?):

allLetters = list('abcdefghijklmnopqrstuvwxyz')
index = random.randint(0, len(allLetters)-1) # Top is inclusive, unlike slices
aiGuess = allLetters[index]
del allLetters[index]

-1voto

serg06 Points 336

Vous pouvez combiner une liste doublement liée et un dictionnaire, pour créer un ensemble avec O(1) choix aléatoire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X