【问题标题】:How can I ask for a key of a subkey in a dictionary in Python?如何在 Python 中的字典中请求子键的键?
【发布时间】:2015-04-28 21:13:27
【问题描述】:

如果我在字典中有一个字典,我如何在恒定时间内请求一个键? 例如:

def get_hobby(hobby):
    d = {'An' : {'Hobby': "Paintball", 'Age' : 22}, 'Jef' : {'Hobby' : "Football", 'Age': 24}, 'Jos' : {'Hobby': "Paintball", 'Age' : 46}}
assert get_hobby("Paintball") == ['An', 'Jos']

这不起作用:

return d.keys[hobby]

【问题讨论】:

  • 您不能在恒定时间内请求密钥,因为您有可变数量的值。
  • 如果您构建了正确的数据结构,您可以在恒定时间内请求密钥。当然,更改数据结构需要线性时间,但只需执行一次,而不是每次查询一次……

标签: python dictionary key


【解决方案1】:

使用列表推导:

return [name for name, props in d.items() if props['Hobby'] == hobby]

d.items() 为您提供(key, value) 对的序列,其中值是嵌套字典。列表推导通过将 hobby 变量与嵌套的 'Hobby' 键匹配来过滤这些,生成过滤器测试返回的名称列表 True

你不能在恒定时间内要求钥匙,因为那个数字是可变的。

演示:

>>> def get_hobby(hobby):
...     d = {'An' : {'Hobby': "Paintball", 'Age' : 22}, 'Jef' : {'Hobby' : "Football", 'Age': 24}, 'Jos' : {'Hobby': "Paintball", 'Age' : 46}}
...     return [name for name, props in d.items() if props['Hobby'] == hobby]
... 
>>> get_hobby("Paintball")
['Jos', 'An']

请注意,返回的键列表是任意顺序,因为字典没有设置顺序。您不能简单地针对另一个列表测试该列表并期望它每次都相等,因为列表确实有顺序。具体顺序取决于Python hash seed 和字典的插入和删除历史。

你可能想要返回一个 set 来代替;集合也没有排序,更好地反映了返回的匹配键的性质:

return {name for name, props in d.items() if props['Hobby'] == hobby}

之后您的断言将变为:

assert get_hobby("Paintball") == {'An', 'Jos'}

【讨论】:

  • @Materials:为了保持一致性,我会坚持使用一个空列表,但如果您需要 None 以获取空结果,您可以将 or None 添加到 return 行。跨度>
  • 恐怕我不能使用name for name的表示法...我可以用其他方式写吗,可能效率低得多?
  • @Materials:然后使用常规循环;创建一个空列表 (results = []),然后使用常规的 for 循环 (for name, props in d.items():) 和 if 过滤器 (if props['Hobby'] == hobby:),并附加限定名称 (results.append(name))。返回results 列表,如果为空则返回None (return results or None)。
【解决方案2】:

这应该可行:

return [key for key, val in d.items() if val['Hobby'] == hobby]

例如:

def get_hobby(hobby):
    d = {
        'An': {'Hobby': "Paintball", 'Age' : 22},
        'Jef': {'Hobby' : "Football", 'Age': 24},
        'Jos' : {'Hobby': "Paintball", 'Age' : 46}
    }
    return [key for key, val in d.items() if val['Hobby'] == hobby]

print get_hobby("Paintball")

结果:

['Jos', 'An']

【讨论】:

    【解决方案3】:

    如果您需要在恒定时间内进行大量此类查询,则必须更改为适当的数据结构。例如:

    d2 = {}
    for name, subdict in d.items():
        for key, value in subdict:
            d2.setdefault((key, value), set()).add(name)
    

    (请注意,我使用的是set,而不是listMartijn Pieters' answer 解释了原因。)

    现在:

    d2['Hobby', 'Paintball']
    

    简单、高效。

    当然,构建数据结构并不需要固定的时间;它显然必须遍历整个字典的每个元素的每个子元素。但是你只做一次,然后你所有的无数查询都是常数时间。所以,只要你能负担得起空间,而“千亿”其实是一个很大的数字,这就是你想要的优化。

    您将需要重组您的代码,以便 dict 实际上构建一次,而不是每次调用get_hobbies。这是否意味着将其放入一个类中,使用闭包,显式地存储在函数上的属性中,或者仅使用在顶层构建的全局变量取决于您。取最后一个,只是因为它最短(可能不是最好的):

    d = {'An' : {'Hobby': "Paintball", 'Age' : 22}, 'Jef' : {'Hobby' : "Football", 'Age': 24}, 'Jos' : {'Hobby': "Paintball", 'Age' : 46}}
    d2 = {}
    for name, subdict in d.items():
        for key, value in subdict:
            d2.setdefault((key, value), set()).add(name)
    
    def get_hobby(hobby):
        return d2['Hobby', hobby]
    
    assert get_hobby("Paintball") == {'An', 'Jos'}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 2014-09-22
      • 2021-03-28
      • 2020-04-01
      • 1970-01-01
      • 2022-08-03
      • 1970-01-01
      相关资源
      最近更新 更多