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?
Here is an iterative approach that will work even if
lineage
does not start at the top of the family tree:Basically, you want to see if you can traverse the tree; use
reduce()
to loop over the elements and if aKeyError
is raised, the path doesn't exist:reduce()
applies thelambda
function recursively tolineage
, starting withfamilytree
.To support finding lineages deeper down the tree, you need to recurse down the tree on
KeyError
s.Demo: