Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I turn this into a recursive function?

I'm trying to create an org chart based on a model that references itself through an attribute called reports_to. I don't know how many levels down the org chart will go, so I feel like a recursive function makes sense. Here's some code that works at the moment:

top_level = Person.objects.filter(reports_to=None)
org_chart = {}
for person in top_level:
    org_chart[person] = {}
    if person.has_direct_reports():
        direct_reports = Person.objects.filter(reports_to=person)
        for p in direct_reports:
            org_chart[person][p] = {}
            if p.has_direct_reports():
                direct_reports_2 = Person.objects.filter(reports_to=p)
                for q in direct_reports_2:
                    org_chart[person][p][q] = {}
                        # ... and so on

This results in a shell output like this:

>>> pp.pprint(org_chart)
{   <Person: Joe Boss>: {   <Person: John Doe>: {   <Person: John Doe Jr>: {   },
                                                          <Person: Jane Doe>: {   }}},
    <Person: Partner Mary>: {}}

Which is correct. Shown cleaner:

Joe Boss
- John Doe
-- John Doe Jr
-- Jane Doe
Partner Mary

I've been trying to convert this code to a recursive function, but my brain just won't get around the problem. Thanks for any advice or help in solving this!

Edit. Here's the code I'm trying to make work, but I'm falling over myself in the process:

def direct_reports_r(person):
    if person.has_direct_reports():
        direct_reports = Person.objects.filter(reports_to=person)
        for person in direct_reports:
            org_chart[person] = {}
            if person.has_direct_reports():
                direct_reports = Person.objects.filter(reports_to=person)
                org_chart[person] = direct_reports_r(person)
            else:
                return person
    else:
        return False

top_level = Person.objects.filter(reports_to=None)
org_chart = {}
for person in top_level:
    org_chart[person] = {}
    # recursion
    org_chart[person][direct_reports_r(person)] = {}
like image 570
hookedonwinter Avatar asked Mar 08 '26 15:03

hookedonwinter


2 Answers

I hope this code works.

def foo(person, tmp_root):
    tmp_root[person] = {}
    if person.has_direct_reports():
        direct_reports = Person.objects.filter(reports_to=person)
        for p in direct_reports:
            foo(p, tmp_root[person])

org_chart = {}
top_level = Person.objects.filter(reports_to=None)
for person in top_level:
    foo(person, org_chart)
like image 167
set0gut1 Avatar answered Mar 11 '26 07:03

set0gut1


Passed lists are mutable, as well as dictionaries so when you pass it into an argument, it's by reference. Here's an example you can play with to achieve the desired result.

top_level = Person.objects.filter(reports_to=None)
org_chart = {}

def init_org_chart(reports, arg):
    for person in reports:
        arg[person] = {}
        if person.has_direct_reports():
            direct_reports = Person.objects.filter(reports_to=person)
            init_org_chart(direct_reports, arg[person])

init_org_chart(top_level, org_chart)
like image 43
Paul Carlton Avatar answered Mar 11 '26 07:03

Paul Carlton



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!