[英]Looping dictionary values
我目前有一個程序,它讀取文本文件並根據內部輸入回答一組查詢。 它有助於弄清楚母親是誰的孩子受到質疑。 我現在更進一步,重新處理這些輸出,以顯示完整的族樹。
這是包含左側父母和右側孩子的文本文件。 下面是要求的查詢,輸出后面跟着查詢。
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
該程序能夠確定母親是誰(感謝Kampu的幫助),但我現在正試圖了解如何獲取這個值,並可能將其附加到新的列表或字典中,在那里無限循環查找任何可能的祖父母。
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")
這就是我到目前為止, REVERSE_MAP
將每個子項映射到字典中的父項。 然后我將父母列入一個新的名單,我打算再次運行以確定他們的父母是誰。 我在這一點上陷入困境,因為我找不到一種優雅的方式來執行整個過程而不創建三個新的列表來保持循環。 目前它的設置方式,我假設我需要通過for
循環追加它們for
或者之后只需split()
值相加以保持所有值相互之間。 理想情況下,我想學習如何循環這個過程,找出每個問題祖先是誰。
我覺得好像我已經掌握了它應該如何看,但我對Python的了解阻止了我的試錯方法的時間效率。
任何幫助將不勝感激!
編輯:鏈接 - http://pastebin.com/vMpT1GvX
編輯2:
def process_commands(commands, relation_dict):
'''Processes the output'''
output = []
for 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 is 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 the file and outputting it'''
file_name = 'relationships.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)
#Now process commands in the 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()
正如@NullUserException所說,樹(或類似的樹)是一個不錯的選擇。 我發布的答案與您為此問題所選擇的內容完全不同。
您可以定義一個知道其名稱的Person對象,並跟蹤其父級是誰。 父級不是名稱,而是另一個Person對象! (有點像鏈表)。 然后,您可以將人員集合保留為單個列表。
在解析文件時,您不斷將人員添加到列表中,同時使用正確的對象更新其子/父屬性。
給予任何人后,只需打印屬性即可找到關系
以下是一種可能的實現(On Python-2.6)。 在這種情況下,文本文件只包含關系。 稍后使用交互式輸入觸發查詢
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:
#First time entry for the 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() for x in names[1].split(',')]
old_mother = search_add_and_return(people,mother)
#Now get the children objects
child_objects = []
for child in children:
old_child = search_add_and_return(people,child)
child_objects.append(old_child)
#All children have been gathered. Link them up
#Set parent in child and add child to parent's 'children'
old_mother.children.extend(child_objects)
for 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 the language and start a loop
while True:
command = raw_input("Enter your command or 0 to 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 is 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 to keep looking up parent till we don't reach a dead end
#And collect names of each ancestor
while True:
person = person.parent
if person is None:
break
ancestor_list.append(person.name)
if ancestor_list:
print ",".join(ancestor_list)
else:
print "No known ancestors"
if __name__ == '__main__':
main()
編輯
由於您希望簡單易懂,因此這是一種使用詞典(單個詞典)來執行您想要的操作的方法
基本思路如下。 您解析文件以形成一個字典,其中鍵是Mother
,值是list of children
。 因此,當您的示例文件被解析時,您會得到一個字典
relation_dict = {'Charlotte': ['Tim'], 'Sue': ['Chad', 'Brenda', 'Harris'], 'Alice': ['John', 'Dick', 'Harry'], 'Brenda': ['Freddy', 'Alice']}
要查找父級,只需搜索名稱是否在字典值中,如果找到則返回密鑰。 如果找不到母親,則返回無
mother = None
for k,v in relation_dict.items():
if name in v:
mother = k
break
return mother
如果你想找到所有的祖先,你只需要重復這個過程,直到返回None
ancestor_list = []
person = name
while True:
person = find_parent(relation_dict,person)
if person == None:
#Top of the ancestor chain found
break
else:
ancestor_list.append(person)
這是Python-2.6中的一個實現。 它假定您的文本文件的結構使得首先存在所有關系,然后是空白行,然后是所有命令。
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()
樣本輸入的輸出是
mother not known
Alice,Brenda,Sue
person not found
No known ancestors
EDIT2
如果你真的想將它進一步分解為函數,那么這就是process_commands
外觀
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
您使用ANCESTOR_LIST_ADD的方式表明它定義為:
global ANCESTOR_LIST_ADD
ANCESTOR_LIST_ADD = []
如果是這種情況並且ANCESTOR_LIST_ADD是全局的,您可以調用遞歸,它將填充祖先,直到有任何:
def lookup_ancestor(child):
ancestor = REVERSE_MAP.get(child)
if ancestor:
ANCESTOR_LIST_ADD.append(ancestor)
lookup_ancestor(ancestor) #recursion
if ancestor not in LINES:
print("Unknown person")
else:
print("No known ancestors")
如果ANCESTOR_LIST_ADD是局部變量,則需要將其作為調用的一部分傳遞:
def lookup_ancestor(child, ANCESTOR_LIST_ADD):
ancestor = REVERSE_MAP.get(child)
if ancestor:
ANCESTOR_LIST_ADD.append(ancestor)
return lookup_ancestor(ancestor, ANCESTOR_LIST_ADD) #recursion
if ancestor not in LINES:
print("Unknown person")
else:
print("No known ancestors")
return ANCESTOR_LIST_ADD
沒有測試過,但一般的想法是使用遞歸。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.