As @NullUserException explains, a tree (or something similar to it) is a good choice. The answer I am posting is a completely different path from what you have chosen for this problem.
You can define a Person object that knows its name and keeps track of who its parent is. A parent is not a name except for another Person object! (Kinda as a linked list). Then you can save the collection of people as a single list.
When analyzing a file, you add people to the list and at the same time update their child / parent attributes with the correct objects.
Later, given any person, it’s just a matter of printing attributes to look for links
The following is a possible implementation (On Python-2.6). The text file in this case contains only relationships. Queries are later run using interactive input.
class Person(object): """Information about a single name""" def __init__(self,name): self.name = name self.parent = None self.children = [] def search_people(people,name): """Searches for a name in known people and returns the corresponding Person object or None if not found""" try: return filter(lambda y: y.name == name,people)[0] except IndexError: return None def search_add_and_return(people,name): """Search for a name in list of people. If not found add to people. Return the Person object in either case""" old_name = search_people(people,name) if old_name is None:
EDIT
Since you want everything to be simple, here is a way to use dictionaries (one dictionary) to do what you want
The main idea is as follows. You analyze the file to create a dictionary, where the key is Mother , and the values are list of children . So, when your sample file is parsed, you get a dictionary like
relation_dict = {'Charlotte': ['Tim'], 'Sue': ['Chad', 'Brenda', 'Harris'], 'Alice': ['John', 'Dick', 'Harry'], 'Brenda': ['Freddy', 'Alice']}
To find a parent, simply search if the name is in dictionary values and returns the key if it is found. If mom is not found, return None
mother = None for k,v in relation_dict.items(): if name in v: mother = k break return mother
If you want to find all the ancestors, you will only need to repeat this process until None is returned
ancestor_list = [] person = name while True: person = find_parent(relation_dict,person) if person == None:
Here's an implementation in Python-2.6. It assumes that your text file is structured in such a way that first there is all the relationships, then an empty line, and then all the commands.
def read_file(file_name): fp = open(file_name,'r') relations = [] commands = [] reading_relations = True for l in fp: l = l.strip('\n') if not l: reading_relations = False continue if reading_relations: relations.append(l.strip()) else: commands.append(l.strip()) fp.close() return relations,commands def form_relation_dict(relations): relation_dict = {} for l in relations: names = l.split(':') mother = names[0].strip() children = [x.strip() for x in names[1].split(',')] existing_children = relation_dict.get(mother,[]) existing_children.extend(children) relation_dict[mother] = existing_children return relation_dict def search_name(relation_dict,name): #Returns True if name occurs anywhere in relation_dict #Else return False for k,v in relation_dict.items(): if name ==k or name in v: return True return False def find_parent(relation_dict,param): #Finds the parent of 'param' in relation_dict #Returns None if no mother found #Returns mother name otherwise mother = None for k,v in relation_dict.items(): if param in v: mother = k break return mother def process_commands(commands,relation_dict): output = [] for c in commands: coms = c.split() if len(coms) < 2: output.append("Invalid Command") continue action = coms[0] param = coms[1] if action == "mother": name_found = search_name(relation_dict,param) if not name_found: output.append("person not found") continue else: person = find_parent(relation_dict,param) if person is None: output.append("mother not known") else: output.append("mother - %s" %(person)) elif action == "ancestors": name_found = search_name(relation_dict,param) if not name_found: output.append("person not found") continue else: #Loop through to find the mother till dead - end (None) is not reached ancestor_list = [] person = param while True: person = find_parent(relation_dict,person) if person == None: #Top of the ancestor found break else: ancestor_list.append(person) if ancestor_list: output.append(",".join(ancestor_list)) else: output.append("No known ancestors") return output def main(): file_name = 'try.txt' relations,commands = read_file(file_name) #Process Relqations to form a dictionary of the type {parent: [child1,child2,...]} relation_dict = form_relation_dict(relations) print relation_dict #Now process commands in the file output = process_commands(commands,relation_dict) print '\n'.join(output) if __name__ == '__main__': main()
Output for entering your sample
mother not known Alice,Brenda,Sue person not found No known ancestors
EDIT2
If you really want to break it down into functions, this is how process_commands should look
def process_mother(relation_dict,name): #Processes the mother command #Returns the ouput string output_str = '' name_found = search_name(relation_dict,name) if not name_found: output_str = "person not found" else: person = find_parent(relation_dict,name) if person is None: output_str = "mother not known" else: output_str = "mother - %s" %(person) return output_str def process_ancestors(relation_dict,name): output_str = '' name_found = search_name(relation_dict,name) if not name_found: output_str = "person not found" else: #Loop through to find the mother till dead - end (None) is not reached ancestor_list = [] person = name while True: person = find_parent(relation_dict,person) if person == None: #Top of the ancestor found break else: ancestor_list.append(person) if ancestor_list: output_str = ",".join(ancestor_list) else: output_str = "No known ancestors" return output_str def process_commands(commands,relation_dict): output = [] for c in commands: coms = c.split() if len(coms) < 2: output.append("Invalid Command") continue action = coms[0] param = coms[1] if action == "mother": new_output = process_mother(relation_dict,param) elif action == "ancestors": new_output = process_ancestors(relation_dict,param) if new_output: output.append(new_output) return output