Home > Back-end >  Save descendence in family tree with a recursive function in Python
Save descendence in family tree with a recursive function in Python

Time:12-07

I have a dictionary of a family tree with the name of the child as the key and their dad's and mom's name in a list as the value.

d = { 
'Kevin': ('Tom', 'Marge'), 
'Marge': ('John', 'Mary'), 
'Elle': ('Tom', 'Marge'), 
'Seth': ('Tom', 'Marge'), 
'Mary': ('Carl', 'Elena'), 
'Tom': ('Joseph', 'Alice'), 
'Alice': ('Rob', 'Amy'), 
'John': ('James', 'Elena'), 
'Joseph': ('Adam', 'Emma'), 
'James': ('Nick', 'Maria') }

I need to write a recursive function so that it returns True when there is a descendence between two people. If there is a descendance, it has to print out the chain of relations, i.e:

>>> print("Is there a lineage?", lineage('Amy', 'Kevin', d))
Amy
Alice
Tom
Kevin
Is there a lineage? True

Otherwise if there isn't one:

>>> print("Is there a lineage?", lineage('Mary', 'Alice', d))
Is there a lineage? False

This is what I've got so far. It seems to return True or False consistantly, but I'm having troubles figuring out how to save the path between the two people.

line = []

def lineage(parent, child, d):
    dad, mom = d[child][0], d[child][1]
    
    try:
        if parent in d[child]:
            line.append(parent)
        else:
            try:
                lineage(parent, dad, d)
            except:
                lineage(parent, mom, d)
        
        return True
    
    except:
        return False

I'm new to recursion, so any ideas or help on how to approach this are much appreciated.

CodePudding user response:

  • I made your function return the path, instead of True, when a path exists.
  • I recommend avoiding try / except here.

It is true that trying to access d[child] without checking that child is in d might result in an Exception. However, this is the base-case of your recursion; your code will be easier to understand if the base case is clearly identified with an explicit if at the beginning of your function, rather than with an obscure "some Exception happened" with no explanation at the end of your function.

def lineage(parent, child, d):
    if parent == child:
        return [child]
    elif child not in d:
        return False
    else:
        dad, mom = d[child][0], d[child][1]
        path_via_dad = lineage(parent, dad, d)
        if path_via_dad:
            path_via_dad.append(child)
            return path_via_dad
        else:
            path_via_mom = lineage(parent, mom, d)
            if path_via_mom:
                path_via_mom.append(child)
                return path_via_mom
            else:
                return False

Here is a shorter, equivalent version, relying on the specific behaviour of logical operator or in python:

def lineage(parent, child, d):
    if parent == child:
        return [child]
    elif child not in d:
        return False
    else:
        dad, mom = d[child][0], d[child][1]
        path = lineage(parent, dad, d) or lineage(parent, mom, d)
        if path:
            path.append(child)
        return path

Testing:

>>> lineage('Amy', 'Kevin', d)
['Amy', 'Alice', 'Tom', 'Kevin']
>>> lineage('Mary', 'Alice', d)
False
  • Related