If I have a dictionary in a dictionary, how can I ask for a key in constant time?
For example:
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']
This doesn't work:
return d.keys[hobby]
解决方案
Use a list comprehension:
return [name for name, props in d.items() if props['Hobby'] == hobby]
d.items() gives you a sequence of (key, value) pairs, where the value is the nested dictionary. The list comprehension filters these by matching the hobby variable to the nested 'Hobby' key, producing a list of the names for which the filter test returns True.
You cannot ask for the keys in constant time, because that number is variable.
Demo:
>>> 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']
Note that the returned list of keys is in arbitrary order, because dictionaries have no set ordering. You cannot simply test that list against another list and expect it to be equal every single time, because lists do have order. The exact order depends on the Python hash seed and the insertion and deletion history of the dictionary.
You may want to return a set instead; sets do not have ordering either and better reflect the nature of the matching keys returned:
return {name for name, props in d.items() if props['Hobby'] == hobby}
after which your assertion would become:
assert get_hobby("Paintball") == {'An', 'Jos'}