Skip to content

Instantly share code, notes, and snippets.

@vvgomes
Created May 20, 2022 15:35
Show Gist options
  • Select an option

  • Save vvgomes/4a15346c4a2cac00cdb77020cd0c4969 to your computer and use it in GitHub Desktop.

Select an option

Save vvgomes/4a15346c4a2cac00cdb77020cd0c4969 to your computer and use it in GitHub Desktop.
/*
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)));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment