ozbrancov ozbrancov - 1 month ago 9
Python Question

Trying to build an Organizational Tree From a List

I have an input file that's in the following format.

Fred,Karl,Technician,2010--Karl,Cathy,VP,2009--Cathy,NULL,CEO,2007--
--Vince,Cathy,Technician,2010


I need to parse this information to where it ends up looking something like this in an output file:

Cathy (CEO) 2007
-Karl (VP) 2009
--Fred (Technician) 2010
-Vince (Technician) 2010


With the CEO at the top, each subordinate should be under their superior. So whatever the second name is, that is the supervisor. The trick is that if an employee has 2 supervisors, they need to be indented twice "--" with their immediate supervisor above.

I've tried iterating through the list and parsing through the "--" and the commas but I'm struggling with the structure itself. This is what I have so far.

with open('org_chart_sample.in', 'r') as reader: # Open the input file
with open('output.out', 'w') as writer: # Make output file writable
reader.readline() # Ignore first line
lines = reader.readlines() # Read input lines

for line in lines: # Parse out input by the -- which separated attributes of people in the org
employees = line.split('--')
hierarchy = [] # Exterior list to aid in hierarchy

for employee in employees: # Logic that adds to the hierarchy list as algorithm runs
info = employee.split(',')
hierarchy.append(info)


I've been stuck on this problem for longer that I'd like to admit :(

Answer

Cool question, it was fun to work on. I tried to be thorough, and it ended up getting kind of long, I hope it's still readable.

Code:

##########################
#Input data cleaned a bit#
##########################
lines = ["Fred,Karl,Technician,2010",
         "Karl,Cathy,VP,2009",
         "Cathy,NULL,CEO,2007",
         "Vince,Cathy,Technician,2010",
         "Mary,NULL,CEO,2010",
         "Steve,Mary,IT,2013"]

##################################
#Worker class to make things neat#
##################################
class Worker(object):
    #Variables assigned to this worker
    __slots__ = ["name","boss","job","year","employees","level"]

    #Initialize this worker with a string in the form of:
    #"name,boss,job,year"
    def __init__(self,line):
        self.name,self.boss,self.job,self.year = line.split(",")
        self.level = 0 if self.boss == "NULL" else -1 #If boss is NULL, they are '0' level
        self.employees = []

    #A function to add another worker as this worker's employee
    def employ(self,worker):
        worker.level = self.level+1
        self.employees.append(worker)

    #This is a recursive function which returns a string of this worker
    #and all of this workers employees (depth first)
    def __repr__(self):
        rep_str = ""
        rep_str += "-"*self.level
        rep_str += str(self.name)+" works for "+str(self.boss)
        rep_str += " as a "+str(self.job)+" since "+str(self.year)+"\n"
        for employee in self.employees:
            rep_str += str(employee)
        return rep_str

########################################
#Prepare to assign the bosses employees#
########################################
#1. Turn all of the lines into worker objects
workers = [Worker(line) for line in lines]

#2. Start from the top level bosses (the ones that had NULL as boss)
boss_level = 0

#3. Get a list of all the workers that have a boss_level of 0
bosses = [w for w in workers if w.level == boss_level]

#While there are still boses looking to employ then keep going
while len(bosses) > 0:
    #For each boss look through all the workers and see if they work for this boss
    #If they do, employ that worker to the boss
    for boss in bosses:
        for worker in workers:
            if worker.level == -1 and boss.name == worker.boss:
                boss.employ(worker)

    #Move down a tier of management to sub-bosses
    #If there are no sub-bosses at this level, then stop, otherwise while loop again
    boss_level += 1
    bosses = [w for w in workers if w.level == boss_level]

##########################
#Printing out the workers#
##########################
#1. Loop through the top bosses and
#   print out them and all their workers
top_bosses = [w for w in workers if w.level == 0]
for top_boss in top_bosses:
    print top_boss

Output:

Cathy works for NULL as a CEO since 2007
-Karl works for Cathy as a VP since 2009
--Fred works for Karl as a Technician since 2010
-Vince works for Cathy as a Technician since 2010

Mary works for NULL as a CEO since 2010
-Steve works for Mary as a IT since 2013