【问题标题】:use recursion in javascript in order to count number of employee working under each manager在javascript中使用递归来计算在每个经理手下工作的员工人数
【发布时间】:2021-07-09 04:50:06
【问题描述】:

我在 javascript 异步函数中使用递归来计算在每个经理手下工作的员工人数。 尝试了解我的函数有什么问题以及为什么它只返回一半的员工

    async function countEmployees(E, count) {
        if (E.employees === 'undefined' || E.employees == null) {
            return 0
        }
        else {
            count += E.employees.length
            E.employees.forEach(async emp => {
                console.log('id:', emp.id, 'count:', count)
                await countEmployees(emp, count)
            })
        }
    }

更新: 我想我解决了!一直在覆盖计数 现在修改后的版本可以使用了

var count 
async function countEmployees(E) {

    if (E.employees === 'undefined' || E.employees == null) {
        return 0
    }
 
    else {
        count += E.employees.length
        for (const ind in E.employees) {

            if (Object.hasOwnProperty.call(E.employees, ind)) {
                const emp = E.employees[ind];
                await countEmployees(emp)
            }
           
        }

    }
    
}

setTimeout(() => {
   console.log(count) }, 5000);

【问题讨论】:

  • 我建议返回数字而不是将其作为参数传递
  • 为什么需要异步?
  • @mplungjan 如果使用async,则有一些await 休眠0 ms,这样UI就不会被阻塞
  • 最好提供一些简单的数据结构来显示您的“错误”,以便其他用户可以调试您的代码
  • @nonopolarity 在我看来,这必须是一个庞大的组织,需要异步来计算员工人数

标签: javascript recursion ecmascript-6 promise


【解决方案1】:

我刚刚采用了这种方法。我不确定你是否真的需要异步功能,但你可以去:

// Assuming you have a data structure similar to this

let employees = {
  id: 1,
  employees: [
    {
      id: 11,
      employees: [
        {
          id: 111,
          employees: []
        },
        {
          id: 112,
          employees: []
        }
      ]
    },
    {
      id: 12,
      employees: [
        {
          id: 121,
          employees: []
        },
        {
          id: 122,
          employees: []
        }
      ]
    }
  ]
};

let count = 0;

function recurseEmployees(employee) {
  count++;
  employee.employees.forEach(emp => {
    recurseEmployees(emp);
  });
}

recurseEmployees(employees);

console.log(count);

【讨论】:

  • @FZs 感谢您指出这一点。用 for ... of 对其进行了测试,然后由于异步行为,在最后一个员工被计算之前记录了计数。
  • 这不是最好的解决方案,但由于问题很不清楚,你不能让它变得更好。 async 在这里是不必要的,并且使代码非常复杂。
  • 谢谢大家的帮助和澄清!
  • 您的函数在任何时候都不会返回一个承诺,以便在一些异步事件(如请求完成或超时)之后解决,所以实际上它会立即运行并且不会返回,直到递归完成,所以 async/await 在这里没有做任何事情。无论如何,正如@FZs 指出的那样,forEach 不能异步迭代。
【解决方案2】:

使用@Patrick 的数据结构,这是异步和同步版本:

注意:

  1. 您的代码使用了nullundefined,而Patrick 使用了一个空数组。您可以随时修改它以适合您的数据结构。
  2. 注意undefined 是一个原始类型,singleundefined。您不需要像在代码中那样双引号
  3. 要检查某个东西是null 还是undefined,我们真的可以只使用foo == null,它是双等号。这称为无效比较。同样,我们可以使用foo != null 来检查它不是null 而不是undefined
  4. 如果您 (a) 解决一点问题,然后让您的解决方案解决问题的“更简单的版本”,递归会更优雅,如下面的代码所示。请注意,reduce() 只是将数组相加,而我在同步版本中并没有那样使用它。但无论哪种方式,都很好。
  5. 如果你使用async函数,注意它返回一个promise,所以我们你得到了counts,你必须用Promise.all()说,所有的counts都得到了,然后你把counts加起来李>

let employees = {
  id: 1,
  employees: [{
      id: 11,
      employees: [{
          id: 111,
          employees: []
        },
        {
          id: 112,
          employees: []
        }
      ]
    },
    {
      id: 12,
      employees: [{
          id: 121,
          employees: []
        },
        {
          id: 122,
          employees: []
        }
      ]
    }
  ]
};

// Asynchronous

async function recurseEmployees(employee) {
  let count = 1;

  if (employee.employees && employee.employees.length !== 0) {
    const allChildrenCounts = await Promise.all(employee.employees.map(emp => recurseEmployees(emp)));
    count += allChildrenCounts.reduce((a, b) => a + b);
  }
  return count;
}

recurseEmployees(employees).then(c => console.log(c));

// Synchronous

function recurseEmployeesSync(employee) {
  let count = 1;

  if (employee.employees && employee.employees.length !== 0) {
    for (const emp of employee.employees)
      count += recurseEmployeesSync(emp);
  }
  return count;
}

console.log(recurseEmployeesSync(employees));

【讨论】:

    【解决方案3】:

    我看不出异步的原因,除非实际使用她的直接下属获取员工本身就是一个异步调用。如果是这样的话,我认为我们可以更简单地使用Promise.all,使用类似这样的东西:

    const countEmployees = async (id) => 
      1 + sum (await Promise.all (
        (await fetchEmployee (id)) .employees .map (countEmployees)
      ))
    

    这取决于一个明显的 sum 助手,它汇总了一个数字数组。我们通过 id 获取员工,找到它的 employees 数组属性,在这些结果上映射 countEmployees,在返回的数组上调用 Promise.all,等待结果,然后将返回的总数相加,为当前员工添加 1 .

    这是幼稚的,需要一些工作才能使其投入生产。它不处理失败案例。如果fetchEmployee 被拒绝,这将失败。但我把修复这个问题留给读者作为练习。

    这是一个带有虚拟fetchEmployee 函数的实现,它返回一个层次结构元素的承诺,其中234 报告给1,其中56报告给2,...,而12 报告给9

    const sum = (ns) => ns.reduce ((a, b) => a + b, 0)
    
    const countEmployees = async (id) => 
      1 + sum (await Promise.all (
        (await fetchEmployee (id)) .employees .map (countEmployees)
      ))
    
    countEmployees (1) .then (console .log)
    <script>/* Dummy implementation */ const fetchEmployee = ((emps) => 
      async (id, employees = emps [id]) => Promise .resolve ({id, employees})
    )([[], [2, 3, 4], [5, 6], [7, 8], [9], [10, 11], [], [], [], [12], [], [], []])</script>

    【讨论】:

      【解决方案4】:

      这里是单行,使用object-scan

      // const objectScan = require('object-scan');
      
      const employees = { id: 1, employees: [{ id: 11, employees: [{ id: 111, employees: [] }, { id: 112, employees: [] }] }, { id: 12, employees: [{ id: 121, employees: [] }, { id: 122, employees: [] }] }] };
      
      const count = objectScan(['**(^employees$).id'], { useArraySelector: false, rtn: 'count' });
      
      console.log(count(employees));
      // => 7
      .as-console-wrapper {max-height: 100% !important; top: 0}
      &lt;script src="https://bundle.run/object-scan@14.3.1"&gt;&lt;/script&gt;

      免责声明:我是object-scan的作者

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-23
        • 1970-01-01
        相关资源
        最近更新 更多