好的,所以我有一本 super 英雄的字典,以他们的名字作为键,还有一本包含大量附加信息的字典:
heroes = {
"Superman": {
"weaknesses": ["kryptonite", "Martha"],
"alter_ego": "Clark Kent",
...},
"Batman": {
"weaknesses": [],
"alter_ego": "Bruce Wayne",
...},
...
}
由于我可能计划闯入城市中的一些庄园,我想确认房主实际上不是英雄,或者至少有足够的信息以便我可以相应地准备。
这种数据结构,查找起来有点笨重
victim_name = "Clark Kent"
# Check if the victim is not the alterego of an hero
def check_victim_is_hero(victim, heroes):
alter_egos = [hero["alter_ego"] for hero in heroes.values()]
return victim in alter_egos
# I can also get the name of the specific hero
def check_which_hero_is_victim(victim, heroes):
for hero_name, hero in heroes.items():
if hero["alter_ego"] == victim:
return hero_name
我可以先获取英雄的名字,然后简单地调用原始字典上的 get
,或者稍微更改 check_wich_hero_is_victim
以返回 hero[ “弱点”]
而不是 hero_name
。
然而,这两种解决方案都迫使我迭代字典,随着我收集的信息的增加,它变得越来越昂贵。
我想要的是有一个对象,我可以从中调用 get
从 super 英雄或 alterego 名称,成本为 O(1)。
类似于:
heroes_double_index = ...
heroes_double_index.get_from_hero_name("Superman")
>>> {"name": "Superman", "alter_ego": "Clark Kent", "weaknesses":...}
heroes_double_index.get_from_alterego("Clark Kent")
>>> {...} Same dictionary as above
我目前的想法是有一个类,其中包含我喜欢的每组键的两个字典:
class DoubleIndexDict:
# Assuming we get the data as a list of records
def __init__(self, data):
self.dict_heroes = {hero["name"]: hero for hero in data}
self.dict_alterego = {hero["alter_ego"]: hero for hero in data}
def get_from_hero_name(self, name):
return self.dict_heroes.get(name)
def get_from_alter_ego(self, name):
return self.dict_alterego.get(name)
但是这并不能完全满足我,最值得注意的是因为我可以在不影响查询完成方式的情况下更改每个字典中的值。
heroes_double_index.get_from_hero_name("Captain America")
>>> {"name": "Captain America", "alter_ego": "Steve Rogers"}
# Make the change
heroes_double_index.dict_heroes["Captain America"]["alter_ego"] = "Isaiah Bradley"
# The difference appears inside of the dictionary
heroes_double_index.get_from_hero_name("Captain America")
>>> {"name": "Captain America", "alter_ego": "Isaiah Bradley"}
# But I cannot use the new alterego for my search
heroes_double_index.get_from_alterego("Isaiah Bradley")
>>> None
是否有任何既定且更有效的方法来做我想在 python 中做的事情?
最佳答案
如果您只想能够在 O(1) 上同时更新 alter_ego 和 name(我认为这不是用于更多 key 的可扩展解决方案),那么您可以这样做:
class Heroes:
def __init__(self, data):
self.id_by_hero = {}
self.id_by_alter_ego = {}
self.data = {}
for i, h in enumerate(data):
self.id_by_hero[h["name"]] = str(i)
self.id_by_alter_ego[h["alter_ego"]] = str(i)
self.data[str(i)] = HeroDict(self, h)
def __getitem__(self, key):
id = self.id_by_hero.get(key) or self.id_by_alter_ego.get(key)
return self.data[id] if id else None
def update_key(self, key, old, new):
if key == "name":
self.id_by_hero[new] = self.id_by_hero.pop(old)
if key == "alter_ego":
self.id_by_alter_ego[new] = self.id_by_alter_ego.pop(old)
class HeroDict(object):
def __init__(self, parent, init=None):
self.parent = parent
if init is not None:
self.__dict__.update(init)
def __setitem__(self, key, value):
old = self.__dict__[key]
self.__dict__[key] = value
self.parent.update_key(key, old, value)
def __repr__(self):
r = self.__dict__.copy()
del r['parent']
return repr(r)
通过将真实数据保存在一个字典中,您不必在每次更改值或选择从何处获取它时都更新它们。然后,当您更新一个值时,它会调用 update_key
并只更新引用。
这样,您将获得:
heroes_double_index["Captain America"]
>>> {'name': 'Captain America', 'weaknesses': [], 'alter_ego': 'Steve Rogers'}
heroes_double_index["Captain America"]["alter_ego"] = "Isaiah Bradley"
heroes_double_index["Captain America"]
>>> {'name': 'Captain America', 'weaknesses': [], 'alter_ego': 'Isaiah Bradley'}
heroes_double_index["Isaiah Bradley"]
>>> {'name': 'Captain America', 'weaknesses': [], 'alter_ego': 'Isaiah Bradley'}
关于python - 使用两组不同的键创建字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63412432/