python - Looping dictionary values -
i have program reads text file , answers set of queries based on input inside. serves figure out mothers of children questioned. i'm taking 1 step further , reprocessing these outputs provided display full family tree.
this text file containing parents on left hand side , kids on right. below queries being asked, followed outputs.
sue: chad, brenda, harris charlotte: tim brenda: freddy, alice alice: john, dick, harry mother sue ancestors harry ancestors bernard ancestors charlotte >>> mother not known >>> alice, brenda, sue >>> unknown person >>> no known ancestors
the program able work out mother (thanks kampu help) i'm trying understand how take value , perhaps append new list or dictionary indefinitely looped find possible grandparents.
def lookup_ancestor(child): ancestor = reverse_map.get(child) if ancestor: ancestor_list_add.append(ancestor) if ancestor not in lines[0:]: print("unknown person") else: print("no known ancestors")
this have far, reverse_map
has each child mapped parent in dictionary. i'm placing parents new list plan run again figure out their parents are. i'm stuck @ point can't find elegant way perform whole process without creating 3 new lists keep looping over. way it's setup @ moment, i'm assuming i'd need either append them via for
loop or split()
values afterwards keep values each other. ideally, i'd learn how loop process , find out each questions ancestors are.
i feel if have grasp on how should possibly knowledge of python prevents trial , error method being time efficient..
any appreciated!
edit: link - http://pastebin.com/vmpt1gvx
edit 2:
def process_commands(commands, relation_dict): '''processes output''' output = [] c in commands: coms = c.split() if len(coms) < 2: output.append("invalid command") continue action = coms[0] param = coms[1] def mother_lookup(action, param, relation_dict): output_a = [] if action == "mother": name_found = search_name(relation_dict, param) if not name_found: output_a.append("unknown person") else: person = find_parent(relation_dict, param) if person none: output_a.append("mother not known") else: output_a.append(person) return output_a def ancestor_lookup(action, param, relation_dict): output_b = [] if action == "ancestors": name_found = search_name(relation_dict, param) if not name_found: output_b.append("unknown person") else: ancestor_list = [] person = param while true: person = find_parent(relation_dict, person) if person == none: break else: ancestor_list.append(person) if ancestor_list: output_b.append(", ".join(ancestor_list)) else: output_b.append("no known ancestors") return output_b def main(): '''definining file , outputting it''' file_name = 'relationships.txt' relations,commands = read_file(file_name) #process relqations form dictionary of type #{parent: [child1,child2,...]} relation_dict = form_relation_dict(relations) #now process commands in file action = process_commands(commands, relation_dict) param = process_commands(commands, relation_dict) output_b = ancestor_lookup(action, param, relation_dict) output_a = mother_lookup(action, param, relation_dict) print('\n'.join(output_a)) print ('\n'.join(output_b)) if __name__ == '__main__': main()
as @nulluserexception said, tree (or resembling it) choice. answer posting quite different track have chosen problem.
you can define person object knows name , keeps track of parent is. parent isn't name person object! (kinda linked list). can keep collection of people single list.
while parsing file, keep adding people list while @ same time updating children/parent attribute correct objects.
later given person, matter of printing attributes find relationships
the following possible implementation (on python-2.6). text file in case contains relationships. queries later fired using interactive input
class person(object): """information single name""" def __init__(self,name): self.name = name self.parent = none self.children = [] def search_people(people,name): """searches name in known people , returns 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 name in list of people. if not found add people. return person object in either case""" old_name = search_people(people,name) if old_name none: #first time entry name old_name = person(name) people.append(old_name) return old_name def read_file(file_name,people): fp = open(file_name,'r') while true: l = fp.readline() l.strip('\n').strip() if not l: break names = l.split(':') mother = names[0].strip() children = [x.strip() x in names[1].split(',')] old_mother = search_add_and_return(people,mother) #now children objects child_objects = [] child in children: old_child = search_add_and_return(people,child) child_objects.append(old_child) #all children have been gathered. link them #set parent in child , add child parent's 'children' old_mother.children.extend(child_objects) c in child_objects: c.parent = old_mother fp.close() def main(): file_name = 'try.txt' people = [] read_file(file_name,people) #now lets define language , start loop while true: command = raw_input("enter command or 0 quit\n") if command == '0': break coms = command.split() if len(coms) < 2: print "wrong command" continue action = coms[0] param = coms[1] if action == "mother": person = search_people(people,param) if person == none: print "person not found" continue else: if person.parent none: print "mother not known" else: print person.parent.name elif action == "ancestors": person = search_people(people,param) if person == none: print "person not found" continue else: ancestor_list = [] #need keep looking parent till don't reach dead end #and collect names of each ancestor while true: person = person.parent if person none: break ancestor_list.append(person.name) if ancestor_list: print ",".join(ancestor_list) else: print "no known ancestors" if __name__ == '__main__': main()
edit
since keep things simple, here way of using dictionaries (a single dictionary) want
the basic idea following. parse file form dictionary key mother
, values list of children
. when sample file parsed, dictionary like
relation_dict = {'charlotte': ['tim'], 'sue': ['chad', 'brenda', 'harris'], 'alice': ['john', 'dick', 'harry'], 'brenda': ['freddy', 'alice']}
to find parent search if name in dictionary values , return key if found. if no mother found, return none
mother = none k,v in relation_dict.items(): if name in v: mother = k break return mother
if want find ancestors, you'll need repeat process till none returned
ancestor_list = [] person = name while true: person = find_parent(relation_dict,person) if person == none: #top of ancestor chain found break else: ancestor_list.append(person)
here's implementation in python-2.6. assumes text file structured such first there relations, blank line , commands.
def read_file(file_name): fp = open(file_name,'r') relations = [] commands = [] reading_relations = true 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 = {} l in relations: names = l.split(':') mother = names[0].strip() children = [x.strip() 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 k,v in relation_dict.items(): if name ==k or name in v: return true return false def find_parent(relation_dict,param): #finds parent of 'param' in relation_dict #returns none if no mother found #returns mother name otherwise mother = none k,v in relation_dict.items(): if param in v: mother = k break return mother def process_commands(commands,relation_dict): output = [] 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 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 find mother till dead - end (none) not reached ancestor_list = [] person = param while true: person = find_parent(relation_dict,person) if person == none: #top of 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 form dictionary of type {parent: [child1,child2,...]} relation_dict = form_relation_dict(relations) print relation_dict #now process commands in file output = process_commands(commands,relation_dict) print '\n'.join(output) if __name__ == '__main__': main()
output sample input is
mother not known alice,brenda,sue person not found no known ancestors
edit2
if want split further functions, here's how process_commands
should look
def process_mother(relation_dict,name): #processes mother command #returns 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 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 find mother till dead - end (none) not reached ancestor_list = [] person = name while true: person = find_parent(relation_dict,person) if person == none: #top of 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 = [] 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
Comments
Post a Comment