random.choice из набора? питон

94

Я работаю над частью игры в угадайку, связанной с искусственным интеллектом. Я хочу, чтобы ИИ выбрал случайную букву из этого списка. Я делаю это как набор, поэтому я могу легко удалять буквы из списка, поскольку они угадываются в игре и поэтому больше не доступны для повторного угадывания.

он говорит, что setобъект не индексируется. Как я могу обойти это?

import random 
aiTurn=True

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



    print (aiGuess) 
Джамын
источник
1
Между прочим, вам не нужно использовать set (list ('string')) для получения набора букв, поскольку строки являются итерируемыми сами по себе - set ('abc') сделает то, что вы хотите.
Скотт Ричи
5
Тем, кто сталкивается с этой проблемой, стоит рассмотреть этот вопрос о том, как создать объект, подобный множеству, который обеспечивает эффективный случайный выбор. Все варианты, указанные здесь, равны O (N). stackoverflow.com/q/15993447/2966723
Джоэл

Ответы:

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

Документация: https://docs.python.org/3/library/random.html#random.sample

NPE
источник
9
Прикрепите [0]в конце, так что он в основном идентичен random.choice(который не возвращает его значения в виде списка)
Nick T
31
random.sampleделает tuple(population)внутренне, так что random.choice(tuple(allLetters))может быть лучше.
utapyngo
21
Следует подчеркнуть, что этот процесс - O (N).
Джоэл
@Joel Почему этот процесс O (N)?
ManuelSchneid3r
2
Я думаю, что это действительно неэффективно ... Как вы можете видеть github.com/python/cpython/blob/2.7/Lib/random.py#L332-L339, примерная функция создает список из набора каждый раз, когда вы делаете вышеуказанный вызов и берет из него случайный элемент. Предположим, у вас большой набор и вы хотите сделать много образцов. Если набор не меняется, лучше преобразовать его в список и использовать random.choice. Если набор также меняется во время отбора проб, то, вероятно, вам вообще не следует использовать набор. Если бы вы знали занятые хэши в наборе и размеры ведра, было бы легко написать функцию выборки ...
jakab922
58

Вы должны использовать random.choice(tuple(myset)), потому что он быстрее и, возможно, чище, чем random.sample. Я написал для проверки следующее:

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

Судя по цифрам, это random.sampleзанимает на 7% больше времени.

Скотт Ричи
источник
2
На моей машине random.choice в 7 раз быстрее.
noɥʇʎԀʎzɐɹƆ
4
Нет возможности выбрать прямо из набора, не копируя его в кортеж?
Youda008
Я получаю выборку примерно на 12% (250 мс) медленнее, чем выбор на наборе из 5000 элементов.
Саймон
1
На моей машине скорость random.sampleпереходит от медленнее, чем random.choiceк скорости, по мере увеличения размера набора (точка пересечения находится где-то между размером набора 100k-500k). То есть, чем больше набор, тем больше вероятность, что он random.sampleбудет быстрее.
Джейки