简体   繁体   English

如何递归打印员工列表及其各自的组织层次结构?

[英]How to recursively print list of employees and their respective organizational hierarchy?

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.例如,“Alice,Heidi,Engineering Manager,Vancouver”表示 Alice 向 Heidi 汇报,Alice 是位于温哥华的工程经理。 Please build a function to print out an org chart in the following format:请构建 function 以打印以下格式的组织结构图:

 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.这是我到目前为止所写的内容,但是在想出正确的逻辑来搜索 object 并打印出层次结构时遇到了麻烦。 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.我知道我可能需要利用递归来遍历嵌套的 object,但我对确切的逻辑需要是什么样子感到有些困惑。

 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: [] } }

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.构建结果后,您可以通过遍历条目并在reports数组中找到具有自己名称的人来识别根名称。 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.之后,很容易将其传递给 function,该 function 使用指定的缩进记录一个人的详细信息,然后迭代该人的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);
    }
  }
};

 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)

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.每次递归调用都会增加一个depth参数,使您能够在每个级别计算正确的填充。

 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);

Your data structure is correctly built.您的数据结构已正确构建。 To identify the root of the tree, spot the employee that is its own manager and in that case don't push that (reflexive) relation into their reports array (so to avoid a circular reference).要识别树的根,请找出作为其自己经理的员工,在这种情况下,不要将该(自反)关系推入他们的reports数组中(以避免循环引用)。

For the output format you can use a recursive function that takes the expected indenting as extra argument.对于 output 格式,您可以使用将预期缩进作为额外参数的递归 function。

In below solution I also rewrote your structure building code, so we have two functions:在下面的解决方案中,我还重写了您的结构构建代码,因此我们有两个功能:

  • makeTree : building the hierarchical data structure (no printing), which as a result returns the root node. makeTree :构建分层数据结构(不打印),结果返回根节点。
  • treeToString : returns the data as a string in the output format. treeToString :将数据作为 output 格式的字符串返回。

 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 makeTree(employeeData) { const employees = Object.fromEntries( employeeData.map(csv => csv.split(",")).map(([person, manager, ...details]) => [person, {person, manager, details, reports: []}] ) ); let root; for (const employee of Object.values(employees)) { if (employee.manager == employee.person) root = employee; else employees[employee.manager].reports.push(employee); } return root; } function treeToString({person, details, reports}, indent="") { return `${indent}${person} [${details.join(", ")}]\n` + reports.map(member => treeToString(member, indent+" ")).join(""); } console.log(treeToString(makeTree(employeeData)));

I would choose a slightly different intermediate representation.我会选择一个稍微不同的中间表示。 I would make the individual employee's nodes somewhat flatter, moving up the title and location fields to their node (removing details ) but also make the whole thing deeper by nesting the employee's direct reports as whole nodes rather than just the string keys.我会让个别员工的节点更扁平,将 title 和 location 字段向上移动到他们的节点(删除details ),但也会通过将员工的直接下属嵌套为整个节点而不仅仅是字符串键,从而使整个事情变得更深。 It might look like this:它可能看起来像这样:

{
  emp: "Grace",
  title: "CEO",
  loc: "SF",
  reports: [
    {
      emp: "Bob",
      title: "Product Director",
      loc: "SF",
      reports: [
        {
          emp: "Charlie",
          title: "Product Manager",
          loc: "Tempe",
          reports: []
        },
        {
          emp: "Frank",
          title: "Designer",
          loc: "SF",
          reports: []
        }
      ]
    },
    /* ... */
  ]
}

In order to do this, I would do a similar breakdown as the other answers suggest.为了做到这一点,我会按照其他答案的建议进行类似的细分。 In this case there are three functions:在这种情况下,有三个功能:

 const toTree = ( rows, [emp, mgr, title, loc] = rows.find (([emp, mgr]) => emp == mgr), reports = rows.filter ((e) => e[1] == emp && e[0],== emp) ) => ({emp, title, loc: reports. reports,map ((r) => toTree (rows. r))}) const parseEmployees = (ss) => toTree (employeeData.map (s => s,split (','))) const display = ({emp, loc, title, reports}, indent = '') => `${indent}${emp} [${title}. ${loc}]\n` + reports,map (rep => display (rep. indent + ' ')),join ('') 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'] console .log (display (parseEmployees (employeeData)))
 .as-console-wrapper {max-height: 100%;important: top: 0}

display takes the structure I describe above and turns it into a useful output string. display采用我上面描述的结构并将其转换为有用的 output 字符串。 Notice the separation of concerns here;注意这里的关注点分离; even this function doesn't call console.log , letting its caller do this.即使这个 function 也不会调用console.log ,让调用者这样做。

parseEmployees splits the input string into separate arrays such as ['Alice', 'Heidi', 'Engineering Manager', 'Vancouver'] , then calls toTree to turn this into the format we've described. parseEmployees将输入字符串拆分为单独的 arrays 例如['Alice', 'Heidi', 'Engineering Manager', 'Vancouver'] ,然后调用toTree将其转换为我们描述的格式。

toTree is the recursive function, looking first for the root node by checking a self-manager situation, turning it into a useful object, and finding its direct reports with recursive calls. toTree是递归的 function,首先通过检查自我管理器情况来寻找根节点,将其变成有用的 object,并通过递归调用找到其直接报告。

The breakdown between the latter two functions could be altered in many interesting ways.后两个功能之间的细分可以通过许多有趣的方式进行更改。 But in the end, you have a structure that describes the whole organization.但最终,您将拥有一个描述整个组织的结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM