Ok, so I have a dictionary of superheroes, with their name as keys, and a dictionary with a bunch of additional info:
heroes = {
"Superman": {
"weaknesses": ["kryptonite", "Martha"],
"alter_ego": "Clark Kent",
...},
"Batman": {
"weaknesses": [],
"alter_ego": "Bruce Wayne",
...},
...
}
As I may plan to break into some manors in the city, I'd like to check that the owner of the house is not in fact a hero, or at least have enough info so that I can prepare accordingly.
With this data structure, the search is a bit cumberstone
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
I can get the weakness by first getting the hero's name, then simply calling get on the original dictionary, or change a bit check_wich_hero_is_victim to return hero["weaknesses"] rather than hero_name.
However, either solution forces me to iterate over the dictionary, which as the information I gather grow, get more and more costly.
What I would like is to have an object from which I could call get either from superhero or alterego name, with a cost of O(1).
Something like:
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
My idea for the moment is to have a class which two dictionaries with each set of key that I like:
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)
However this does not fully satisfy me, most notably because I can change the values from inside each dictionary without affecting the way the query is done.
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
Is there any established and more efficient way to do what I am trying to do in python ?