Home > Software design >  How to recursively print list of employees and their respective organizational hierarchy?
How to recursively print list of employees and their respective organizational hierarchy?

Time:09-12

You are given a list of strings containing data about an organization structure.

Input example:

const employeeData = [
    'Alice,Heidi,Engineering Manager,Vancouver',
    'Bob,Grace,Product Director,SF',
    'Charlie,Bob,Product Manager,Tempe',
    'David,Alice,Software Developer,Bangalore',
    'Eve,Heidi,Principal Engineer,SF',
    'Frank,Bob,Designer,SF',
    'Grace,Grace,CEO,SF',
    'Heidi,Grace,CTO,SF',
    'Ivan,Grace,Operations Director,SF',
]

For example, 'Alice,Heidi,Engineering Manager,Vancouver' means that Alice reports to Heidi, and Alice is an Engineering Manager located in Vancouver. Please build a function to print out an org chart in the following format:

Grace [CEO, SF]
   Bob [Product Director, SF]
     Charlie [Product Manager, Tempe]
     Frank [Designer, SF]
   Heidi [CTO, SF]
     Alice [Engineering Manager, Vancouver]
       David [Software Developer, Bangalore]
     Eve [Principal Engineer, SF]
   Ivan [Operations Director, SF]

This is what I've written so far, but am having trouble coming up with the right logic to search through the object and print out the hierarchy. I know that I'll probably need to utilize recursion to iterate through the nested object, but I'm getting a bit tripped up on what the exact logic needs to look like.

function printOrgChart(employeeData) {
    const results = {};
    const formatted = employeeData.map((employee) => employee.split(','));
    for (let i = 0; i < formatted.length; i  ) {
        let person = formatted[i][0];
        let manager = formatted[i][1];
        let role = formatted[i][2];
        let location = formatted[i][3];
        console.log(results);
        if (results.hasOwnProperty(manager)) {
            results[manager]['reports'].push(person);
        } else {
            results[manager] = {
                details: [],
                reports: [person],
            };
        }
        if (results.hasOwnProperty(person)) {
            results[person]['details'].push(role, location);
        } else {
            results[person] = {
                details: [role, location],
                reports: [],
            };
        }
    }
    console.log(results);
}

This is what I have so far:

{ Heidi: { details: [ 'CTO', 'SF' ], reports: [ 'Alice', 'Eve' ] },
  Alice: 
   { details: [ 'Engineering Manager', 'Vancouver' ],
     reports: [ 'David' ] },
  Grace: 
   { details: [ 'CEO', 'SF' ],
     reports: [ 'Bob', 'Grace', 'Heidi', 'Ivan' ] },
  Bob: 
   { details: [ 'Product Director', 'SF' ],
     reports: [ 'Charlie', 'Frank' ] },
  Charlie: { details: [ 'Product Manager', 'Tempe' ], reports: [] },
  David: { details: [ 'Software Developer', 'Bangalore' ], reports: [] },
  Eve: { details: [ 'Principal Engineer', 'SF' ], reports: [] },
  Frank: { details: [ 'Designer', 'SF' ], reports: [] },
  Ivan: { details: [ 'Operations Director', 'SF' ], reports: [] } }

CodePudding user response:

Once you've constructed the results, you can identify the root name by iterating through the entries and finding the one who has their own name in their reports array. After that, it's simple to pass that onto a function that logs a person's details, with a specified indent, then iterates through that person's reports and does the same thing with an increased indent.

const rootName = Object.entries(results).find(([name, { reports }]) => reports.includes(name))[0];
display(results, rootName);
const display = (results, name, indent = 0) => {
  const { details, reports } = results[name];
  console.log(`${' '.repeat(indent)}${name} [${details[0]}, ${details[1]}]`);
  for (const reportsToThis of reports) {
    if (reportsToThis !== name) {
      display(results, reportsToThis, indent   3);
    }
  }
};

const employeeData = [
    'Alice,Heidi,Engineering Manager,Vancouver',
    'Bob,Grace,Product Director,SF',
    'Charlie,Bob,Product Manager,Tempe',
    'David,Alice,Software Developer,Bangalore',
    'Eve,Heidi,Principal Engineer,SF',
    'Frank,Bob,Designer,SF',
    'Grace,Grace,CEO,SF',
    'Heidi,Grace,CTO,SF',
    'Ivan,Grace,Operations Director,SF',
]
function printOrgChart(employeeData) {
    const results = {};
    const formatted = employeeData.map((employee) => employee.split(','));
    for (let i = 0; i < formatted.length; i  ) {
        let person = formatted[i][0];
        let manager = formatted[i][1];
        let role = formatted[i][2];
        let location = formatted[i][3];
        if (results.hasOwnProperty(manager)) {
            results[manager]['reports'].push(person);
        } else {
            results[manager] = {
                details: [],
                reports: [person],
            };
        }
        if (results.hasOwnProperty(person)) {
            results[person]['details'].push(role, location);
        } else {
            results[person] = {
                details: [role, location],
                reports: [],
            };
        }
    }
    const rootName = Object.entries(results).find(([name, { reports }]) => reports.includes(name))[0];
    display(results, rootName);
}
const display = (results, name, indent = 0) => {
  const { details, reports } = results[name];
  console.log(`${' '.repeat(indent)}${name} [${details[0]}, ${details[1]}]`);
  for (const reportsToThis of reports) {
    if (reportsToThis !== name) {
      display(results, reportsToThis, indent   3);
    }
  }
};
printOrgChart(employeeData)

CodePudding user response:

Your approach creates a good data structure that maps managers to their reports, but the missing piece is code to walk the structure as a tree and print it formatted to the specification.

You can do this with recursion or a stack. A depth parameter is incremented for every recursive call, enabling you to compute the correct padding at each level.

const employeeData = [
  'Alice,Heidi,Engineering Manager,Vancouver',
  'Bob,Grace,Product Director,SF',
  'Charlie,Bob,Product Manager,Tempe',
  'David,Alice,Software Developer,Bangalore',
  'Eve,Heidi,Principal Engineer,SF',
  'Frank,Bob,Designer,SF',
  'Grace,Grace,CEO,SF',
  'Heidi,Grace,CTO,SF',
  'Ivan,Grace,Operations Director,SF',
];
const reports = {};
let root;

for (const e of employeeData) {
  const [name, mgr, pos, loc] = e.split(",");

  if (!reports[mgr]) {
    reports[mgr] = [];
  }

  if (name === mgr) {
    root = {name, pos, loc};
  }
  else {
    reports[mgr].push({name, pos, loc});
  }
}

const print = ({name, pos, loc}, tree, depth=0) => {
  const pad = " ".repeat(depth * 2);
  console.log(`${pad}${name} [${pos}, ${loc}]`);
  tree[name]?.forEach(e => print(e, tree, depth   1));
};
print(root, reports);

  • Related