Вытяните случайные ключи из словаря в Python, которые не равны друг другу

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

У меня есть словарь. В этом словаре я хочу получить 3 случайных ключа. Я также хочу убедиться, что эти три ключа не равны (другими словами, случайны друг от друга). Вот код, который я написал до сих пор:

import random

word_drills = {'class': 'Tell Python to make a new kind of thing.',
               'object': 'Two meanings: the most basic kind of thing, and any instance of some thing.',
               'instance': 'What you get when you tell Python to create a class.',
               'def': 'How you define a function inside a class.',
               'self': 'Inside the functions in a class, self is a variable for the instance/object being accessed.',
               'inheritance': 'The concept that one class can inherit traits from another class, much like you and your parents.',
               'composition': 'The concept that a class can be composed of other classes as parts, much like how a car has wheels.',
               'attribute': 'A property classes have that are from composition and are usually variables.',
               'is-a': 'A phrase to say that something inherits from another, as in a Salmon *** Fish',
               'has-a': 'A phrase to say that something is composed of other things or has a trait, as in a Salmon *** mouth.'}

key1 = ' '
key2 = ' '
key3 = ' '             

def nodupchoice():
    while key1 == key2 == key3: 
        key1 = random.choice(word_drills.keys())
        key2 = random.choice(word_drills.keys())
        key3 = random.choice(word_drills.keys())


nodupchoice()

print "Key #1: %s, Key #2: %s, Key #3: %s" % (key1, key2, key3)

Я почти уверен, что проблема связана с моим циклом while. Я хотел создать функцию, которая будет работать до тех пор, пока все три клавиши не будут отличаться друг от друга. Наконец, он напечатает результат. Любые идеи? Заранее спасибо.


person kiddsupreme    schedule 18.08.2012    source источник
comment
Просто чтобы улучшить свой вопрос: вы ссылаетесь на проблему, но неясно, что происходит, когда вы запускаете свой код.   -  person Argalatyr    schedule 19.08.2012


Ответы (6)


Вы можете использовать random.sample:

>>> random.sample(word_drills, 3)
['has-a', 'attribute', 'instance']

и .keys() не надо, итерация по словарю идет по ключам.

Обратите внимание, что random.sample вернет три уникальных значения из предоставленного вами списка (т. е. никогда не вернет 'has-a' дважды):

>>> all(len(set(random.sample(word_drills, 3))) == 3 for i in range(10**5))
True
person DSM    schedule 18.08.2012
comment
Ничего себе, теперь я чувствую себя немного простодушным. Определенно упрощает то, что я пытался сделать. Однако у меня есть дополнительный вопрос. Хотя он возвращает нужную мне информацию, как мне присвоить результат переменным key1, key2 и key3? - person kiddsupreme; 19.08.2012
comment
Я предлагаю вам работать со списком ключей и просто использовать keys = random.sample(word_drills, 3), а получать к ним доступ с помощью keys[0], keys[1] и keys[2]. В 90% случаев, когда вы используете числовые суффиксы в именах переменных, это признак того, что вам действительно нужен список, кортеж или словарь. Но если вам нужны три отдельных имени, вы можете просто написать key1, key2, key3 = random.sample(word_drills, 3). - person DSM; 19.08.2012
comment
Потрясающий. Спасибо ДСМ! Просто еще один быстрый вопрос. Списки изменяемы, верно? Так что, если я буду запускать это снова и снова, элементы в списке также должны измениться? - person kiddsupreme; 19.08.2012
comment
Да, предметы будут (в общем случае, могут случайно повторяться) каждый раз разные. Однако изменчивость списка — это нечто другое, это просто означает, что вы можете написать somelist[2] = 18 и изменить то, на что ссылается somelist[2]. Вы не можете сделать это для кортежей. - person DSM; 19.08.2012
comment
Думаю, теперь, когда я думаю об этом, у меня был еще один вопрос. В конце концов, я хотел, чтобы моя программа не только брала 3 случайных ключа, но и брала одно из значений, соответствующих правильному ответу. По сути, программа предоставит одно из значений ключей в качестве вопроса. Затем пользователь будет выбирать между 3 случайными ключами. Если выбранный ключ совпадает со значением в словаре, пользователь будет прав. В противном случае ответ будет неверным. Имеет ли это смысл? - person kiddsupreme; 19.08.2012
comment
Разделы комментариев — не лучшее место для обсуждения. Вы знаете, как сопоставлять ключи со значениями — например, word_drills[key1] — это значение, соответствующее key1, — так что можете попробовать. Возможно, вам будет полезно прочитать раздел словаря официального учебника. Это не должно быть слишком плохо. :^) Удачи! - person DSM; 19.08.2012
comment
Еще раз спасибо DSM, ценю это! - person kiddsupreme; 19.08.2012
comment
Для Python3 вам нужно сначала преобразовать его в список: random.sample(list(word_drills), 3). - person erik; 25.08.2016

Используйте 1_

>>> import random
>>> random.sample([1,2,3,4,5,6], 3)
[4, 5, 2]
person applicative_functor    schedule 18.08.2012

Может быть, вы хотели бы попробовать Quiz Me 2.5? Это система викторин с несколькими вариантами ответов с графическим интерфейсом на Python 3.x.

person Noctis Skytower    schedule 18.08.2012

Как объясняли другие, random.sample — лучший способ сделать то, что вы хотеть.

Чтобы объяснить, почему ваш исходный код не работал:

Первая проблема, в вашем цикле while есть логическая ошибка - он завершится, как только два элемента станут разными (например, 'a' == 'a' == 'b' равно True, и цикл завершится), чтобы исправить это, есть несколько способов:

while not (key1 != key2 != key3):

В качестве альтернативы set может содержать только уникальные элементы, поэтому, когда длина set([key1, key2, key3]) равна 3, все три значения различны:

while len(set([key1, key2, key3]) != 3:

Вторая проблема и причина, по которой код отказывается запускаться:

key1 key2 key3 определены как глобальные переменные (файл key1 = ' ' are at the top-level of your.py`, а не в функции)

Вы можете без проблем найти глобальную переменную в функции (например, где вы сделали while key1 == key2 ...). Ошибка возникает из-за того, что вы также пытаетесь назначить значение key1 в своем цикле — это сбивает с толку синтаксический анализатор Python, поскольку вы ищете глобальную переменную в части while key1 == ..., но пытаетесь создать новую локальную переменную функции. на следующей строке, поэтому он выдает ошибку.

Мусорный способ исправить это выглядит так:

key1 = ' '
key2 = ' '
key3 = ' '             

def nodupchoice():
    global key1
    global key2
    global key3
    while not (key1 != key2 != key3):
        key1 = random.choice(word_drills.keys())
        key2 = random.choice(word_drills.keys())
        key3 = random.choice(word_drills.keys())

Тогда это будет работать так, как вы предполагали, но не делайте этого - глобальные переменные имеют свое применение, но это не та ситуация..

Вместо использования глобальной переменной вы можете легко вернуть несколько значений из функции:

def nodupchoice():
    key1 = ' ' # local variables, which are inaccessible outside this function
    key2 = ' '
    key3 = ' '

    while not (key1 != key2 != key3):
        key1 = random.choice(word_drills.keys())
        key2 = random.choice(word_drills.keys())
        key3 = random.choice(word_drills.keys())

    return key1, key2, key3


key1, key2, key3 = nodupchoice()

print "Key #1: %s, Key #2: %s, Key #3: %s" % (key1, key2, key3)

О, и даже лучше, вы можете передать word_drills в качестве аргумента:

def nodupchoice(things):
    key1 = ' ' # local variables, which are inaccessible outside this function
    key2 = ' '
    key3 = ' '

    while not (key1 != key2 != key3):
        key1 = random.choice(things)
        key2 = random.choice(things)
        key3 = random.choice(things)

    return key1, key2, key3


key1, key2, key3 = nodupchoice(word_drills)

... и вы написали функцию, почти идентичную random.sample(word_drills, 3)!

person dbr    schedule 18.08.2012
comment
Однако в исходном коде есть логическая ошибка. Цикл while завершится, как только окажется неверным, что три ключа одинаковы, а это не то же самое, что три разных ключа. Например, он перестанет пытаться, если два одинаковых, а третий отличается. - person DSM; 19.08.2012
comment
'a' == 'a' == 'b' не верно. Кроме того, while not (key1 != key2 != key3): не является исправлением (key1 может быть равно key3). - person Reinstate Monica; 10.04.2014

Наверное, проще всего shuffle ключи:

keysShuffled = list(word_drills)
random.shuffle(keysShuffled)

Затем возьмите первые 3

threeUnique = keysShuffled[:3]
person Doug T.    schedule 18.08.2012
comment
shuffle работает на месте и возвращает None, поэтому это не будет работать так, как написано. Однако keys = list(word_drills); random.shuffle(keys) сработает. - person DSM; 19.08.2012

У меня была такая же проблема, и я написал https://github.com/robtandy/randomdict, чтобы решить ее. Может быть, это поможет и вам.

Он предоставляет объект python dict, но с дополнительными методами random_key, random_value и random_item. Все со сложностью выполнения O(1).

person Rob T    schedule 27.09.2015