问题
First of all, here is the question and the code written:
def family_lineage(familytree, lineage):
'''(dict, list of strs) -> boolean
Return True if lineage specifies a list of names who are directly related
in a chain of parent-child relationships, and NOT child-parent, parent-grandchild..etc,
beginning from the first generation listed.
>>> trace_lineage({'Gina': {'Sam': {'Tina': {}},
'Li': {}},
'Guy': {}},
['Gina'])
True
>>> trace_lineage({'Gina': {'Sam': {'Tina': {}},
'Li': {}},
'Guy': {}},
['Gina', 'Sam', 'Tina'])
True
>>> trace_lineage({'Gina': {'Sam': {'Tina': {}},
'Li': {}},
'Guy': {}},
['Gina', 'Tina'])
False
'''
So, in the above example, it shows the 'Guy' has no children, and 'Gina' has two children, 'Sam', and 'Li'. 'Sam' has one child, 'Tina'.
for k, v in familytree.items():
for n, m in v.items():
if lineage[0] == any(k) and len(lineage) == 1:
return True
elif lineage[0] == k and lineage[1] == n and len(lineage) ==2:
return True
elif lineage[0] == k and lineage[1] == n and lineage[2] == m and \
len(lineage) == 3:
return True
else:
return False
So, my question is, how would I write this if the familytree extended beyond three generations? Is there a more concise way of writing this code?
回答1:
Here is an iterative approach that will work even if lineage
does not start at the top of the family tree:
def family_lineage(familytree, lineage):
trees = [familytree]
while trees:
tree = trees.pop()
trees.extend(t for t in tree.values() if t)
for name in lineage:
if name not in tree:
break
tree = tree[name]
else:
return True
return False
回答2:
Basically, you want to see if you can traverse the tree; use reduce() to loop over the elements and if a KeyError
is raised, the path doesn't exist:
def family_lineage(familytree, lineage):
if not familytree:
return False
try:
reduce(lambda d, k: d[k], lineage, familytree)
return True
except KeyError:
# No match at this level, recurse down the family tree
return any(family_lineage(val, lineage) for val in familytree.itervalues())
reduce()
applies the lambda
function recursively to lineage
, starting with familytree
.
To support finding lineages deeper down the tree, you need to recurse down the tree on KeyError
s.
Demo:
>>> tree = {'Gina': {'Sam': {'Tina': {}}, 'Li': {}}, 'Guy': {}}
>>> family_lineage(tree, ['Gina'])
True
>>> family_lineage(tree, ['Gina', 'Sam', 'Tina'])
True
>>> family_lineage(tree, ['Gina', 'Tina'])
False
>>> family_lineage(tree, ['Sam', 'Tina'])
True
来源:https://stackoverflow.com/questions/17797489/python-iterating-through-nested-dictionaries