从 Python 中的字典中提取不相等的随机键

Posted

技术标签:

【中文标题】从 Python 中的字典中提取不相等的随机键【英文标题】:Pull random keys from dictionary in Python that are not equal to one another 【发布时间】:2012-08-14 20:56:16 【问题描述】:

所以我正在尝试通过 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 循环上。我想创建一个函数,它会一直运行直到所有三个键都不同。最后,它将打印结果。有任何想法吗?提前致谢。

【问题讨论】:

只是为了帮助改进您的问题:您指的是“问题”,但不清楚运行代码时会发生什么。 【参考方案1】:

你可以使用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

【讨论】:

哇,我现在感觉有点头脑简单。绝对简化了我试图做的事情。不过,我确实有一个后续问题。虽然它返回了我想要的信息,但我如何将结果分配给变量 key1、key2 和 key3? 我建议您使用密钥列表本身,只需使用keys = random.sample(word_drills, 3),并通过keys[0]keys[1]keys[2] 访问它们。 90% 的情况下,当您在变量名中使用数字后缀时,这表明您确实想要一个列表、元组或字典。但是如果你想要三个不同的名字,你可以简单地写key1, key2, key3 = random.sample(word_drills, 3) 太棒了。感谢帝斯曼!还有一个快速的问题。列表是可变的吗?所以如果我一遍又一遍地运行这个,列表中的项目也应该改变? 是的,这些项目(通常;可能会偶然重复)每次都不同。但是,列表可变性有所不同,这仅意味着您可以编写 somelist[2] = 18 并更改 somelist[2] 所指的内容。你不能对元组这样做。 我想我现在确实有另一个问题,因为我正在考虑这个问题。最终,我希望我的程序不仅能抓取 3 个随机键,而且还能抓取“正确”答案的对应值之一。基本上,该程序将提供关键“值”之一作为问题。然后用户将在 3 个随机密钥之间进行选择。如果选择的键与字典中的值匹配,则用户是正确的。否则,答案将是错误的。这有意义吗?【参考方案2】:

使用random.sample

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

【讨论】:

【参考方案3】:

也许你想试试Quiz Me 2.5?它是一个在 Python 3.x 中带有 GUI 的多项选择测验系统。

【讨论】:

【参考方案4】:

正如其他人所解释的,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 ... 所做的那样)。发生错误是因为您还尝试在循环中 assignkey1 - 这会使 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())

然后它会按你的意愿工作,但不要那样做 - 全局变量have their uses,但这不是这种情况..

您可以轻松地从函数返回多个值,而不是使用全局变量:

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) 相同!

【讨论】:

原代码中存在逻辑错误。一旦三个键不一样,while 循环就会结束,这与三个键不同是不一样的。例如,如果两个相同而第三个不同,它将停止尝试。 'a' == 'a' == 'b'不是 True。此外,while not (key1 != key2 != key3):不是修复(key1 可能等于 key3)。【参考方案5】:

可能最简单的做法是shuffle 键:

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

然后取前3个

threeUnique = keysShuffled[:3]

【讨论】:

shuffle 在原地工作并返回 None,所以这不会像写的那样工作。不过keys = list(word_drills); random.shuffle(keys) 会起作用。【参考方案6】:

我遇到了同样的问题并写了https://github.com/robtandy/randomdict 来解决它。也许它也会帮助你。

它提供了一个 python dict 对象,但带有额外的方法,random_key、random_value 和 random_item。所有这些都具有 O(1) 的运行时间复杂度。

【讨论】:

以上是关于从 Python 中的字典中提取不相等的随机键的主要内容,如果未能解决你的问题,请参考以下文章

如何在不从参考节点获取所有数据的情况下获取 Firebase 数据库中的随机键?

Python 在 O(1) 中的字典中获取随机键

如何从 Python 中的字典中提取所有值?

从python中的字典中提取最大值和最小值

从 csv 中提取列中的数据,保存为字典(Python、Pandas)

如何从 Python Pandas Dataframe 中的 STRING 列中提取嵌套字典?