/* The goal of this exercise is to render an org chart in your terminal output based on a list of manager- employee relationships. Given the following relationships: [ { managerId: 1, employeeId: 2 }, { managerId: 0, employeeId: 3 }, { managerId: 0, employeeId: 1 }, { managerId: 0, employeeId: 0 }, ] We expect the following output: 0 |_1 |_2 |_3 The solution below is based on a tree datastructure as an intermediate representation for the org chart and the aggregation algorithm follows a recursive approach combined with the Resequencer pattern as described here: https://www.enterpriseintegrationpatterns.com/patterns/messaging/Resequencer.html */ const relationships = [ { managerId: 1, employeeId: 11 }, { managerId: 0, employeeId: 2 }, { managerId: 1, employeeId: 12 }, { managerId: 0, employeeId: 0 }, { managerId: 2, employeeId: 21 }, { managerId: 0, employeeId: 1 }, { managerId: 2, employeeId: 22 }, ]; function findEmployee(id, root) { if (!Object.keys(root).length) return; if (id === root.id) return root; return root.reports.find(e => findEmployee(id, e)); } function findInBuffer(id, buffer) { return buffer.find(e => e.id === id); } function addToBuffer(e, buffer) { return buffer.concat(e); } function removeFromBuffer(id, buffer) { return buffer.filter(e => e.id !== id); } function createEmployee(id, reports = []) { return { id, reports }; } function consume(input, index = 0, output = {}, buffer = []) { if (index > input.length - 1) return output; let updatedBuffer; const { managerId, employeeId } = input[index]; // finding employee const employeeFromBuffer = findInBuffer(employeeId, buffer); if (employeeFromBuffer) updatedBuffer = removeFromBuffer(employeeId, buffer); const employee = employeeFromBuffer || createEmployee(employeeId); // it's the ceo if (employeeId === managerId) return consume(input, index + 1, employee, updatedBuffer || buffer); // it's not the ceo const existingManager = findEmployee(managerId, output) || findInBuffer(managerId, buffer); const manager = existingManager || createEmployee(managerId); manager.reports.push(employee); if (!existingManager) updatedBuffer = addToBuffer(manager, updatedBuffer || buffer); return consume(input, index + 1, output, updatedBuffer || buffer); } function renderOffset(level) { if (level === 0) return ""; return Array(level - 1) .fill(" ", 0, level - 1) .join("") .concat("|_"); } function renderOrgChart(root, level = 0) { const offset = renderOffset(level); const id = offset.concat(root.id); const reports = root.reports.map(report => renderOrgChart(report, level + 1)); return [id].concat(reports).join("\n"); } console.log(renderOrgChart(consume(relationships)));